为什么cls.__name__不出现在dir()中?
假设我有一个简单的类:
class Foobar(object):
pass
如果我使用 dir(Foobar)
,我会得到以下输出:
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
虽然在 dir()
的输出中没有显示,但我仍然可以访问 __name__
:
Foobar.__name__
并且可以得到 Foobar
。
为什么Python会这样呢?
4 个回答
最近关于这个问题的重复提问让我想更详细地解释一下这个答案。首先,大家接受的答案是对的。dir
这个函数其实是调用了 __dir__
这个特殊的方法,而默认的 __dir__
方法通常只是返回对象的 __dict__
中的键。
其次,__name__
并不在 object.__dict__
中,也不会出现在子类的 __dict__
里。如果它不在 __dict__
里,那它在哪里呢?又是怎么被查找的呢?
根据我对 源代码 的理解,有一些描述符是在类创建时由 type
设置的。其中一个描述符就是 __name__
。__name__
的获取方法会调用 type_name,而设置方法会调用 type_set_name。这些获取和设置方法实际上是在类型对象实例(也就是类)的 tp_name
这个位置上获取或设置名称。由于这是类型对象的一个特殊位置,所以它并不在类的 __dict__
中,因此通过 vars
或 dir
是无法看到的。
需要注意的是,类型对象实例(也就是类)的 dir
方法特别不包括来自 __class__
属性的成员,因为 “属于 metaclass 的方法可能会让人更困惑,而不是更有帮助”。
那么,让我们把这些内容整理一下。
object
没有__name__
属性,但type
有。type
的__name__
属性实际上是一个描述符。- 由于
object
的 metaclass 是type
,当请求object.__name__
时,会调用type
的__name__
描述符。 name
描述符会在type->tp_name
这个位置查找名称。这个位置是由type.__new__
在类创建时填充的。object.__dir__
是特别设计的,不报告类的 metaclass 上的属性,因为 Python 开发者认为这样做会弊大于利。
dir
这个命令并不能保证会返回所有可能的属性。根据官方文档的说明:
因为
dir()
主要是为了方便在交互式提示符下使用,所以它更倾向于提供一组有趣的名称,而不是严格或一致地定义一组名称。而且它的具体表现可能会随着版本的更新而变化。例如,当你传入一个类作为参数时,元类的属性不会出现在结果列表中。