在Python中,有什么方法测试生成器对象以找出哪个生成器创建了它?
给定一个生成器对象,是否可以测试它是由哪个特定的生成器创建的?换句话说,我们能否判断这个生成器的“类型”是什么?因为生成器对象的类型是 generator
,所以用 type
或 isinstance
来测试是行不通的。
看看下面的代码:
>>> def gen1():
... yield 1
...
>>> def gen2():
... yield 2
...
>>> g1 = gen1()
>>> g2 = gen2()
>>>
>>> def do_something(f):
... # need to know if f is a gen1 generator or a gen2 generator here
... # isinstance(f, gen1) raises a TypeError since gen1 is not a type
... # type(f) is gen1 returns false
... print(f)
...
>>> do_something(g1)
<generator object gen1 at 0x100dcb370>
>>> do_something(g2)
<generator object gen2 at 0x100dcb3c0>
需要注意的是,如果我用一个迭代器类来实现生成器,那么 type
和 isinstance
就可以正常工作,因为生成的对象会是迭代器类所定义的类型:
>>> class gen():
... def __next__(self):
... return 1
...
>>> f = gen()
>>> type(f) is gen
True
>>> isinstance(f, gen)
True
有没有可能以简单的方式实现同样的功能(而不需要像把生成器放在一个类里面,或者使用装饰器之类的方式)来处理那些使用 yield
创建的生成器呢?
1 个回答
6
生成函数的名字(如果有的话)会以字符串的形式存储在 __name__
属性里。如果你只需要这个名字,那就可以结束了。
但如果你想获取实际的函数对象,那就有点复杂了。生成器本身并不持有对函数对象的引用,它的逻辑是通过一个代码对象的引用来运作的。
function object (`gen1`) -----> <code object >
^
generator object (`g1`) -----------╯
有了生成函数的原始名字,你可以尝试在包含它的模块上使用 getattr
来获取最初的函数。不过,这种方法并不一定可靠:这里假设函数对象仍然存在,并且仍然和那个名字绑定在一起。但实际上,那个名字可能已经被删除或者重新绑定了。在 CPython 中,如果引用计数降到 0,函数也可能已经被垃圾回收了。