繁体   English   中英

python:生成器对象上的属性

[英]python: attributes on a generator object

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

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

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

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

谢谢

是。

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

不幸的是,生成器对象(调用生成器函数返回的结果)不支持添加任意属性。 可以通过使用外部字典由发电机对象索引解决它在一定程度上,因为这样的对象可用作为键成一个字典。 那么,你想这样做,说:

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])

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

如果您想查询它们以进行调试,那么以下函数将有所帮助:

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
"""

如果您想询问它们以实现功能,那么实现迭代器协议的类可能是更好的主意。

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

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

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

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

您的代码可以稍后只检查生成器的变量,而不是存储并稍后读取一些其他属性,使用:

filter.gi_frame.f_locals

我想Ants Aasma暗示了这一点。

关于这个问题的思考, 存在具有发电机周围的一组属性进行的一种方式。 这有点疯狂 - 我强烈推荐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 当然,这段代码可能太聪明了一半。 谨慎使用。

我刚刚在这里写了一个装饰器: http//code.activestate.com/recipes/577057-generator-attributes/

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM