为什么Python的生成器不是类型?

Sah*_*and 3 python generator

问题的简短版本:为什么生成器实例的类型不是创建实例的生成器函数?也就是说,如果我们有一个生成器,说是def G(): yield 1并且g是由G它创建的生成器实例g = G(),那么为什么是type(g) is G假的?

细节:

我最近问了一个关于如何确定给定生成器对象的生成器类型的问题.(参见在Python中,有没有办法测试生成器对象以找出哪个生成器创建它?.)答案最终需要使用__name__.但是,这仍然给我一个未解答的问题:为什么生成器不是Python中的类型?

下面的所有代码都考虑到了Python 3.3,但我相信大部分代码都适用于旧版本的Python(至少2.7版本)和更新版本,即3.4版本.

让我们看一个非常简单的迭代器示例,该迭代器首先作为类实现:

class C(object):
    def __iter__(self):
        return self

    def __next__(self):
        return 1


c = C()
print(next(c))       # 1
print(type(c))       # <class '__main__.C'>
print(type(c) is C)  # True
Run Code Online (Sandbox Code Playgroud)

在功能上,上面的类与下面给出的生成器相同.(当然,我们失踪了throw,send而且close,还有其他微妙的差异,但我认为它们与手头的问题无关.)

def G():
    while True:
        yield 1


g = G()
print(next(g))       # 1
print(type(g))       # <class 'generator'>
print(type(g) is G)  # False
Run Code Online (Sandbox Code Playgroud)

但正如您所看到的,使用defyield使用类创建的生成器创建的对象类型和使用类创建的迭代器的处理方式完全不同.所有生成器实例都被赋予泛型类型generator.对我来说,这类似于给出通用类型的类创建的所有对象,比如object当然不是这种情况.

Python总体上是一种非常一致和逻辑的语言.特别是,Python对类型的处理非常一致:对象的"创建者"成为它的类型.即使使用元类,这也很好用:

class M(type):
    def __new__(cls, *args):
        return super().__new__(cls, *args)

class C(metaclass=M):
    pass


c = C()

print(type(c) is C)        # True
print(type(C) is M)        # True
print(type(M) is type)     # True
print(type(type) is type)  # True
Run Code Online (Sandbox Code Playgroud)

你可以在这里看到,type(c)C因为c被创建C,并且type(C)M因为类对象C由元类来创建M,最后M本身是由元类来创建一个类的对象type.我们甚至拥有type(type)is type,它是一个自引用,为类型层次结构提供了一个根.

但是,对于生成器,我觉得这种一致性被打破了.在上面,当我们拥有时g = G(),该对象g实际上是由创建的G.不应该将它的类型设置为等于G?或者,对于我未能看到的所有生成器实例选择泛型类型有更深层次的原因吗?

use*_*ica 5

特别是,Python对类型的处理非常一致:对象的"创建者"成为它的类型.

这仅适用于课程.并非创建对象的所有内容都是类:

type(open('whatever')) is not open
type(iter(whatever)) is not iter
type(compile('whatever')) is not compile
Run Code Online (Sandbox Code Playgroud)

生成器函数是函数,而不是类.你不能对它进行子类化,或者在它上面定义方法,或者让它从某些东西继承,或者改变它的元类,或者做几乎你可以用真实类做的任何事情.学习创建生成器的函数不会改变与它交互的方式,就像学习对象类改变了与对象交互的方式一样.与不同的类不同,无论创建生成器的函数是什么,它都提供完全相同的API.

简而言之,生成函数类型而不是函数没有任何好处.