[译] PEP 3155--类和方法的特定名称
PEP 原文 : https://www.python.org/dev/peps/pep-3155/ (opens new window)
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
2
3
你可以从C.f
对象中获得其所属的类:
>>> C.f.im_class
<class '__main__.C'>
2
这种用法在 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__']
2
3
4
5
6
7
8
9
10
11
12
这就限制了用户可以使用的自省能力。当将程序移植到 Python 3 时,它可能会产生一些实际的问题,例如在 Twisted 的核心代码中,就多次使用到了这种自省方法。此外,这还限制了对 pickle 序列化的支持 (opens new window) [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'
2
3
4
5
6
7
8
9
10
11
12
13
# 嵌套函数的示例
>>> def f():
... def g(): pass
... return g
...
>>> f.__qualname__
'f'
>>> f().__qualname__
'f.<locals>.g'
2
3
4
5
6
7
8
# 不足之处
对于嵌套函数(以及在函数内部定义的类),由于无法从外部获得函数的命名空间,因此点式路径无法以动态编程的方式遍历。相比于空的__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 (opens new window)