2009-06-05 78 views
5

是否可以在生成器对象上创建属性?python:生成器对象上的属性

这里是一个非常简单的例子:

def filter(x): 
    for line in myContent: 
     if line == x: 
      yield x 

现在说我有很多这样的滤波器产生物体漂浮......也许他们中的一些是匿名。我想以后回去审问他们为他们过滤的东西。有没有一种方法可以:a)询问发生器对象的x值,或b)设置一个属性值为x,以后我可以查询它?

谢谢

回答

6

不幸的是,发电机对象(从结果调用生成函数返回)不支持将任意的属性。您可以通过使用由生成器对象索引的外部字典在某种程度上解决它,因为这些对象可用作字典中的键。那么,你最好喜欢做,说:

a = filter(23) 
b = filter(45) 
... 
a.foo = 67 
... 
x = random.choice([a,b]) 
if hasattr(x, 'foo'): munge(x.foo) 

你可以改为做:

foos = dict() 
a = filter(23) 
b = filter(45) 
... 
foos[a] = 67 
... 
x = random.choice([a,b]) 
if x in foos: munge(foos[x]) 

对于任何爱好者,而不是使用一个发电机(一个或一个以上的类的类的毕竟,方法可以是生成器)。

16

是的。

class Filter(object): 
    def __init__(self, content): 
     self.content = content 
    def __call__(self, someParam): 
     self.someParam = someParam 
     for line in self.content: 
      if line == someParam: 
       yield line 
2

不可以。您不能在生成器上设置任意属性。

由于·洛指出,你可以有一个对象,看起来像发电机,并行为就像一台发电机。如果它看起来像一只鸭子,并且像一只鸭子一样行事,那么你就有了鸭子打字的定义。

但是,如果没有适当的代理方法,它将不支持像gi_frame这样的生成器属性。

0

关于这个问题的思考,让发电机携带一组属性的一种方法。这有点疯狂 - 我强烈建议Alex Martelli的建议,而不是这个 - 但它在某些情况下可能会有用。

my_content = ['cat', 'dog days', 'catfish', 'dog', 'catalog'] 

def filter(x): 
    _query = 'I\'m looking for %r' % x 

    def _filter(): 
     query = yield None 
     for line in my_content: 
      while query: 
       query = yield _query 

      if line.startswith(x): 
       query = yield line 

     while query: 
      query = yield _query 

    _f = _filter() 
    _f.next() 
    return _f 

for d in filter('dog'): 
    print 'Found %s' % d 

cats = filter('cat') 
for c in cats: 
    looking = cats.send(True) 
    print 'Found %s (filter %r)' % (c, looking) 

如果你要问什么发电机它的过滤功能,只需拨打send与计算结果为真的值。当然,这个代码可能太聪明了一半。谨慎使用。

3

如果你想询问他们进行调试,那么下面的功能将帮助:

import inspect 

def inspect_generator(g): 
    sourcecode = open(g.gi_code.co_filename).readlines() 
    gline = g.gi_code.co_firstlineno 
    generator_code = inspect.getblock(sourcecode[gline-1:]) 

    output = "Generator %r from %r\n" % (g.gi_code.co_name, g.gi_code.co_filename) 
    output += "".join("%4s: %s" % (idx+gline, line) for idx, line in enumerate(generator_code)) 

    output += "Local variables:\n" 
    output += "".join("%s = %r\n" % (key,value) for key,value in g.gi_frame.f_locals.items()) 

    return output 

print inspect_generator(filter(6)) 
"""Output: 
Generator 'filter' from 'generator_introspection.py' 
    1: def filter(x): 
    2:  for line in myContent: 
    3:   if line == x: 
    4:    yield x 
Local variables: 
x = 6 
""" 

如果你想询问他们执行的功能则实现了迭代器协议类可能是一个更好的主意。

0

我意识到这是一个非常迟来的答案,但...

不是存储后来读了一些附加的属性,你的代码可能后来只是检查发电机的变量(一个或多个),使用:

filter.gi_frame.f_locals

我想蚂蚁Aasma暗示了这一点。

+0

我试过你的建议来检查发生器的变量。它的工作原理是“StopIteration”尚未达到。之后,`gi_frame`变成`None`。 – bli 2017-02-03 16:14:13