[译] PEP 3155--类和方法的特定名称

PEP 原文 : https://www.python.org/dev/peps/pep-3155/

PEP 标题: PEP 3155 – Qualified name for classes and functions

PEP 作者: Antoine Pitrou

创建日期: 2011-10-29

合入版本: 3.3

译者 :豌豆花下猫@Python 猫公众号

PEP 翻译计划https://github.com/chinesehuazhou/peps-cn

原理

一直以来,对于嵌套类的自省,Python 的支持很不够。给定一个类对象,根本不可能知道它是在某个类中定义的,还是在顶层模块中定义的;而且,如果是前者,也不可能知道它具体是在哪个类中定义的。虽然嵌套类通常被认为是不太好的用法,但这不应该成为不支持内层自省的理由。

Python 3 因为丢弃了以前的未绑定方法(unbound method),而受到了侮辱性的伤害。

在 Python 2 中,给出以下定义:

class C:
def f():
pass

你可以从C.f 对象中获得其所属的类:

>>> C.f.im_class
<class '__main__.C'>

这种用法在 Python 3 中已经没有了:

>>> C.f.im_class
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'function' object has no attribute 'im_class'
>>> dir(C.f)
['__annotations__', '__call__', '__class__', '__closure__', '__code__',
'__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__',
'__eq__', '__format__', '__ge__', '__get__', '__getattribute__',
'__globals__', '__gt__', '__hash__', '__init__', '__kwdefaults__',
'__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__']

这就限制了用户可以使用的自省能力。当将程序移植到 Python 3 时,它可能会产生一些实际的问题,例如在 Twisted 的核心代码中,就多次使用到了这种自省方法。此外,这还限制了对 pickle 序列化的支持 [1]。

提议

本 PEP 提议在函数和类中添加 __qualname__ 属性。

对于顶层的函数和类,__qualname__ 属性等于__name__ 属性。对于嵌套的类、方法和嵌套函数,__qualname__ 属性包含一个点式路径(dotted path),通向顶层模块下的对象。函数的局部命名空间在点式路径中由名为 \<locals> 的组件表示。

函数和类的 repr() 和 str() 被修改为使用__qualname__ 而不再是__name__。

嵌套类的示例

>>> class C:
... def f(): pass
... class D:
... def g(): pass
...
>>> C.__qualname__
'C'
>>> C.f.__qualname__
'C.f'
>>> C.D.__qualname__
'C.D'
>>> C.D.g.__qualname__
'C.D.g'

嵌套函数的示例

>>> def f():
... def g(): pass
... return g
...
>>> f.__qualname__
'f'
>>> f().__qualname__
'f.<locals>.g'

不足之处

对于嵌套函数(以及在函数内部定义的类),由于无法从外部获得函数的命名空间,因此点式路径无法以动态编程的方式遍历。相比于空的__name__,它对于人类读者还是有些帮助的。

跟__name__属性一样,__qualname__ 属性是静态计算的,不会自动地重新绑定。

讨论

去除模块名称

跟__name__一样,__ qualname__ 不包含模块的名称。这使得它不受制于模块别名和重新绑定,也得以在编译期进行计算。

恢复 unbound 方法

恢复 unbound 方法只能解决此 PEP 解决了的部分问题,而且代价更高(额外的对象类型和额外的间接寻址,不如用额外的属性)。

命名的选择

简而言之,“Qualified name”是新加属性的最佳表达。(译注:不知道如何准确翻译此处的 Qualified?)

它不是“full name”或“fully qualified name”,因为它(故意)不包括模块的名称。将其称为“path”,则可能会与文件系统的路径及__file__属性混淆。

关于这个属性的名称,最初的建议是将其命名为__qname__,但是许多人却认为它晦涩难懂(他们不知道这个术语已有先例,例如用在了 XML 规范[2]中),这就是为什么这个稍微长点但更明确的__qualname__ 会被选中的原因。

相关链接

[1] “pickle should support methods”: http://bugs.python.org/issue9276

[2] “QName” 在 Wikipedia 的解释: http://en.wikipedia.org/wiki/QName

版权

本文档已进入公共领域。

源文档: https://github.com/python/peps/blob/master/pep-3155.txt