在Python中,有什么方法测试生成器对象以找出哪个生成器创建了它?

4 投票
1 回答
703 浏览
提问于 2025-04-17 22:12

给定一个生成器对象,是否可以测试它是由哪个特定的生成器创建的?换句话说,我们能否判断这个生成器的“类型”是什么?因为生成器对象的类型是 generator,所以用 typeisinstance 来测试是行不通的。

看看下面的代码:

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

需要注意的是,如果我用一个迭代器类来实现生成器,那么 typeisinstance 就可以正常工作,因为生成的对象会是迭代器类所定义的类型:

>>> 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,函数也可能已经被垃圾回收了。

撰写回答