【问题标题】:In Python, is there any way to test a generator object to find out which generator created it?在 Python 中,有没有办法测试生成器对象以找出创建它的生成器?
【发布时间】:2014-03-13 19:58:29
【问题描述】:

给定一个生成器对象,是否可以测试它是否由给定的生成器创建?也许更好的说法是,是否可以测试我们拥有的生成器的“类型”?由于生成器对象的类型为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 创建的生成器以简单的方式实现相同的功能(例如,无需将生成器包装在类中或使用装饰器)?

【问题讨论】:

    标签: python


    【解决方案1】:

    生成函数的名称(如果有)以字符串形式存储在__name__ 属性中。如果字符串是您所需要的,那么您就完成了。

    要获取实际的函数对象,这很复杂。生成器本身不包含对函数对象的任何引用,并且逻辑使用对代码对象的引用进行操作。

    function object (`gen1`) -----> <code object >
                                        ^
    generator object (`g1`)  -----------╯
    

    有了生成器函数的原始名称,您可以想象在包含模块上使用getattr 来尝试检索原始函数。这种方法不一定可靠:这里假设函数对象仍然存在并且仍然绑定到该名称。但是,该名称可能已被删除或反弹。在 CPython 中,如果引用计数减少到 0,该函数也可能已经被垃圾回收。

    【讨论】:

    • 谢谢,这行得通。知道为什么type 不返回生成器函数,就像它对类创建的对象一样?我认为这与 Python 的其他部分不一致。
    • 其实并没有矛盾——我想你只是误解了对象模型。 gen1types.FunctionType 的实例,g1types.GeneratorType 的实例
    • 要查看您可能出错的地方,请考虑一下 - 如果 g1gen1 的实例,那么 g1_ = (1 for x in 'abc') 会是什么实例?
    • 我同意gen1 应该是FunctionType 类型,但我仍然认为g1 应该是gen1 类型以与Python 的其余部分保持一致。考虑一个事实,一个类的类型是它的元类,而一个对象的类型是它的类。换句话说,对象的类型被设置为创建它们的对象。例如,创建类的元类和创建对象的类。
    • 但是gen1只是一个名字,它不是一个类型!
    猜你喜欢
    • 2018-11-21
    • 2022-06-25
    • 1970-01-01
    • 2014-09-28
    • 2018-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-27
    相关资源
    最近更新 更多