在 Python 3 中类型就是类 (就 repr() 而言)

78 阅读3分钟

昨天的文章中,我写了一个小插曲,说 "repr() ,被认为是'类型'和被认为是'类'之间的区别有些武断"。事实证明,这在Python 3中是不正确的,这暴露了Python 2和Python 3之间有趣的区别,也暴露了一点Python 1和Python 2的旧历史。

(所以我这篇旧文章中的侧边栏并不适用于Python 3)。

首先,让我们展示一下Python 2中的情况:

>>> class A:
...     pass
>>> class B(object):
...     pass
>>> repr(A)
'<class __main__.A at 0x7fd804cacf30>'
>>> repr(B)
"<class '__main__.B'>"
>>> repr(type)
"<type 'type'>"

Python 2 中的旧式和新式类的报告方式略有不同,但它们都是 "类",而type (或任何其它内置类型,如int)是 "类型"。这种区分是在一个相当低的层次上进行的,正如我的旧条目的侧边栏中所描述的那样。

然而,在 Python 3 中事情发生了变化,repr()'的输出是统一的:

>>> class B(object):
...   pass
>>> repr(B)
"<class '__main__.B'>"
>>> repr(type)
"<class 'type'>"

Python 类和内置类型都是'类'。这个变化是在Python 3中特别引入的,作为问题2565(这个变化出现在3.0a5中)。 这个问题的讨论中对这里发生的事情有一个提示。

简化一下,在 Python 1.x 中,类和内置类型之间没有统一。作为这种差异的一部分,它们的repr() 结果以你期望的方式不同;一个说 "类",另一个说 "类型"。当Python 2.0出现时,它用新式的类统一了类型。这种统一的最初实现导致repr() 将新的风格类报告为类型。然而,在 2.x 开发初期的某个时刻,这段代码被修改为报告新的样式类为'class ...'。为了向后兼容 Python 1.x 中repr() 的输出,对内置类型的报告没有改变。在 Python 3 的开发过程中,这种向后兼容被移除,现在所有的内置类型(或者如果你愿意的话,类)都被报告为类。

(我本来想说一些关于type() 报告的内容,但后来我真的想了一下。实际上,type() 并不报告任何类型的字符串;type() 返回一个对象,如果你只是在交互式会话中运行,解释器会使用str() 打印它,对于类来说,它通常与repr() 相同。在我的交互式例子中使用 'repr(B)' 而不是 'type(B)' 的原因是 'type(B)' 是type 。)

旁白:2001年时代变化的实际提交信息

第2565期没有引用完整的提交信息,结果发现省略的部分很有意思(尤其是这是Guido van Rossum做的修改):

将新式类的repr()改为<class 'ClassName'>而不是<type 'ClassName'>。 例外:如果它是一个内置类型或扩展类型,继续叫它<type 'ClassName>。 你可以说我是个懦夫,但我不想破坏更多的用户代码,而不是必要的。

就我从阅读旧的 Python 更新日志中可以看出,这个变化出现在 Python 2.2a4。在某种程度上,这在Python 2.x的开发中是出乎意料的晚。关于这个变化的'what's new'片段重申,不改变内置类型的输出是为了向后兼容:

新式类的 repr() 已经改变;代替 <type 'M.Foo'> 的是新式类现在被呈现为 <class 'M.Foo'>,除了内置类型,它们仍然被呈现为 <type 'Foo'> (以避免扰乱可能解析或依赖某些类型对象 repr() 的现有代码)。

当然,在那个时候,这也是为了与依赖2.0和2.1中内置类型的repr()报告的人们兼容。