如何在生成器函数对象实例中存储和检索元信息?

时间:2012-04-24 03:02:27

标签: python

有没有一种方法可以向实例化生成器函数的调用者返回更多信息,而不仅仅是函数实例本身?

例如,

def genFn(a, b, c):
    # some initialisation / pre-computation
    startPt = fn(a, b, c)
    data = (yield None)
    while True:
        # perform some computation
        data = (yield result)

f = genFn(5, 6, 7)
start = f.get("startPt") # this line syntax is wrong - just to show what I want
f.send(None)
for data in dataseries[startPt:]:
    k = f.send(data)
    ...

基于传入的参数(a,b,c),该函数具有计算其所需的最早数据的逻辑。我喜欢以某种方式将这些信息“它需要的最早数据”返回给调用者。虽然我当然可以让调用者计算并获得相同的信息 - 这是一种重复工作,但它并不优雅,因为我想在生成器函数中封装复杂性。

由于

Ť

2 个答案:

答案 0 :(得分:1)

您可以将其作为第一个send来电的当前未使用的返回值返回。

def genFn(a, b, c):
    # some initialisation / pre-computation
    startPt = fn(a, b, c)
    data = (yield startPt)
    while True:
        # perform some computation
        data = (yield result)

f = genFn(5, 6, 7)
startPt = f.send(None)  # first yield returns the start point
for data in dataseries[startPt:]:
    k = f.send(data)

顺便说一下,.send(None).next()相同。

或者您可以使用类并使用生成器作为其方法之一。预计算将在__init__中完成,数据可以通过实例属性进行访问。

class GenCl(object):
    def __init__(self, a, b, c):
        self.startPt = fn(a, b, c)

    def gen(self):
        startPt = self.startPt  # get the startPt calculated in __init__
        data = (yield None)
        while True:
            # perform some computation
            data = (yield result)

o = genCl(5, 6, 7)
startPt = o.startPt
f = o.gen()  # create the generator object
f.send(None)
for data in dataseries[startPt:]:
    k = f.send(data)

另一个想法是使用闭包。函数调用将返回生成器和起始点,例如在元组中。

def genFn(a, b, c):
    # some initialisation / pre-computation
    startPt = fn(a, b, c)
    def gen():  # actual generator function
        data = (yield None)
        while True:
            # perform some computation
            data = (yield result)
    return gen(), startPt  # returns generator and startPt

f, startPt = genFn(5, 6, 7)
f.send(None)
for data in dataseries[startPt:]:
    k = f.send(data)

答案 1 :(得分:0)

您可以创建一个特殊的类,可以将其发送到生成器以使其返回您的特殊值。

class GetStartPt:
    pass

def genFn(a, b, c):
    startPt = fn(a, b, c)
    data = (yield None)
    while True:
        if data is GetStartPt:
            data = (yield startPt)
            continue
        # compute here
        data = (yield result)

f = genFn(5, 6, 7)
f.send(GetStartPt)

但是,你可能最好为此编写一个包装类:

class GenClass(object):
     def __init__(self, a, b, c):
         self.startPt = fn(a, b, c)
         def generator(startPt, a, b c):
             data = (yield None)
                 while True:
                 # compute here
             data = (yield result)
         self._generator = generator(self.startPt, a, b, c)
     def __iter__(self):
         return self._generator
     def next(self):
         return self._generator.next()
     def send(self, value):
         return self.generator.send(value)