Python:生成器对象的属性

6 投票
7 回答
13644 浏览
提问于 2025-04-15 12:03

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

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

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

现在假设我有很多这样的过滤生成器对象在使用……可能其中一些是匿名的……我想在之后回去查看它们在过滤什么。我有没有办法可以 a) 查询生成器对象的 x 值,或者 b) 设置一个属性,给 x 赋值,以便我可以在之后查询?

谢谢

7 个回答

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

如果你想要检查它们是为了实现某些功能,那么使用实现了迭代器协议的类可能会更好。

19

是的。

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
8

很遗憾,生成器对象(也就是调用生成器函数后得到的结果)不支持添加任意属性。不过,你可以通过使用一个外部的字典来解决这个问题,因为生成器对象可以作为字典的键。也就是说,如果你想这样做:

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

如果你需要更复杂的功能,可以考虑使用类来代替生成器(毕竟,类中的一个或多个方法可以是生成器)。

撰写回答