是否可以在生成器对象上创建属性?
这是一个非常简单的例子:
def filter(x):
for line in myContent:
if line == x:
yield x
现在说我有很多这些过滤器生成器对象浮动...可能其中一些是匿名的...我想稍后再回过头来询问他们过滤的内容。有没有办法我可以a)询问生成器对象的x值或b)设置一个值为x的属性我以后可以查询?
由于
答案 0 :(得分: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
答案 1 :(得分:7)
不幸的是,生成器对象(调用生成器函数返回的结果)不支持添加任意属性。您可以通过使用由生成器对象索引的外部字典在某种程度上解决它,因为此类对象 可用作dict的键。那么你喜欢做什么,比如说:
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])
对于任何爱好者来说,使用类而不是生成器(毕竟,类的一个或多个方法可以是生成器)。
答案 2 :(得分: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
"""
如果您想询问它们以实现功能,那么实现迭代器协议的类可能是更好的主意。
答案 3 :(得分:2)
没有。您无法在生成器上设置任意属性。
正如S. Lott指出的那样,你可以拥有一个看起来的对象,就像一个生成器,而就像生成器一样。如果它看起来像一只鸭子,就像一只鸭子,那么你就可以自己定义鸭子打字了。
但是,如果没有适当的代理方法,它将不支持gi_frame
等生成器属性。
答案 4 :(得分: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)
如果您想询问生成器它的过滤内容,只需使用值为true的值调用send
。当然,这段代码可能太聪明了一半。请谨慎使用。
答案 5 :(得分:0)
我意识到这是一个非常迟来的答案,但是......
您的代码可以稍后检查生成器的变量,而不是存储并稍后读取一些其他属性,使用:
filter.gi_frame.f_locals
我想Ants Aasma暗示了这一点。
答案 6 :(得分:-1)
我刚刚写了一个装饰器来做这个: http://code.activestate.com/recipes/577057-generator-attributes/