python:生成器对象上的属性

时间:2009-06-05 15:39:55

标签: python

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

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

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

现在说我有很多这些过滤器生成器对象浮动...可能其中一些是匿名的...我想稍后再回过头来询问他们过滤的内容。有没有办法我可以a)询问生成器对象的x值或b)设置一个值为x的属性我以后可以查询?

由于

7 个答案:

答案 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/