当我使用 dir([user-defined object]) 时,为什么它也 return 对象父 class 的名称空间中的名称?
When I use dir([user-defined object]), why does it also return the names in the namespace of the object's parent class?
dir() 函数,如果没有给定参数,returns 当前本地范围内的名称列表。但是,如果我们给参数,它 returns 给定对象参数的属性名称空间内的名称(即对象的属性)。知道这一点,考虑以下 class:
>>> class Foo():
classVar=23
def __init__(self,x):
print("dir in init:",dir())
self.x=x
def getx(self):
return self.x
当我调用 dir(Foo)
时,它 returns 在 class 对象 Foo 中定义的名称列表(a.k.a Foo 的属性列表)如下:
>>> dir(Foo)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'classVar', 'getx']
如果我执行以下操作:
>>> newFoo=Foo(17)
dir in init: ['self', 'x'] #list of names in the local variable namespace from the __init__ method call.
>>> dir(newFoo) #called from the global scope
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'classVar', 'getx', 'x']
我们可以看到 newFoo
的属性列表(在 newFoo
的属性命名空间中定义的名称)还包括在其父 class 中定义的名称,例如 getx
,以及 classVar
。我认为 dir()
可能不仅返回本地命名空间,还返回封闭的命名空间。我使用一个函数对此进行了测试,但它只返回本地命名空间内的名称,而不是封闭的命名空间。我想知道为什么用户定义 classes/objects 会出现这种情况。当我无法使用 dir()
访问函数调用中的封闭命名空间时,为什么我还能在父 class 的命名空间中看到名称?
class 的名称空间不包含 其实例的名称空间。事实上,对象的属性访问 obj.attr
经历了不同的阶段:
- 检查对象类型的 data descriptor named
attr
exists in the method resolution order 是否为:type(obj).mro()
.
- 检查
obj.__dict__
中是否存在"attr"
。
- 检查MRO中是否存在
attr
- 最后,如果上面的none成功并且定义了
__getattr__
,它将以"attr"
作为参数被调用。
以上步骤由 object.__getattribute__
处理,可以在自定义 classes 中覆盖。
另请注意,类型可以通过定义 __dir__
.
自由自定义 dir(obj)
返回的内容
同样重要的是要注意没有 class 范围 包含例如class 定义中的函数定义(参见 Python Scopes and Namespaces)。从以下示例可以看出这是一个常见的陷阱:
>>> class Test:
... x = 1
... y = [i*x for i in range(5)]
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in Test
File "<stdin>", line 3, in <listcomp>
NameError: name 'x' is not defined
这里的列表理解定义了它自己的范围,并尝试根据 LEGB rule(其中“E”代表“封闭”)解析名称 x
。但是,由于 class 定义不是正确的范围,因此在名称解析期间无法搜索它。
dir() 函数,如果没有给定参数,returns 当前本地范围内的名称列表。但是,如果我们给参数,它 returns 给定对象参数的属性名称空间内的名称(即对象的属性)。知道这一点,考虑以下 class:
>>> class Foo():
classVar=23
def __init__(self,x):
print("dir in init:",dir())
self.x=x
def getx(self):
return self.x
当我调用 dir(Foo)
时,它 returns 在 class 对象 Foo 中定义的名称列表(a.k.a Foo 的属性列表)如下:
>>> dir(Foo)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'classVar', 'getx']
如果我执行以下操作:
>>> newFoo=Foo(17)
dir in init: ['self', 'x'] #list of names in the local variable namespace from the __init__ method call.
>>> dir(newFoo) #called from the global scope
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'classVar', 'getx', 'x']
我们可以看到 newFoo
的属性列表(在 newFoo
的属性命名空间中定义的名称)还包括在其父 class 中定义的名称,例如 getx
,以及 classVar
。我认为 dir()
可能不仅返回本地命名空间,还返回封闭的命名空间。我使用一个函数对此进行了测试,但它只返回本地命名空间内的名称,而不是封闭的命名空间。我想知道为什么用户定义 classes/objects 会出现这种情况。当我无法使用 dir()
访问函数调用中的封闭命名空间时,为什么我还能在父 class 的命名空间中看到名称?
class 的名称空间不包含 其实例的名称空间。事实上,对象的属性访问 obj.attr
经历了不同的阶段:
- 检查对象类型的 data descriptor named
attr
exists in the method resolution order 是否为:type(obj).mro()
. - 检查
obj.__dict__
中是否存在"attr"
。 - 检查MRO中是否存在
attr
- 最后,如果上面的none成功并且定义了
__getattr__
,它将以"attr"
作为参数被调用。
以上步骤由 object.__getattribute__
处理,可以在自定义 classes 中覆盖。
另请注意,类型可以通过定义 __dir__
.
dir(obj)
返回的内容
同样重要的是要注意没有 class 范围 包含例如class 定义中的函数定义(参见 Python Scopes and Namespaces)。从以下示例可以看出这是一个常见的陷阱:
>>> class Test:
... x = 1
... y = [i*x for i in range(5)]
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in Test
File "<stdin>", line 3, in <listcomp>
NameError: name 'x' is not defined
这里的列表理解定义了它自己的范围,并尝试根据 LEGB rule(其中“E”代表“封闭”)解析名称 x
。但是,由于 class 定义不是正确的范围,因此在名称解析期间无法搜索它。