Python 为什么在dir(MyClass)中没有出现mro?
输出:Python 为什么在dir(MyClass)中没有出现mro?,python,method-resolution-order,Python,Method Resolution Order,输出: class MyClass(object): pass print MyClass.__mro__ print dir(MyClass) (,) “UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU
class MyClass(object):
pass
print MyClass.__mro__
print dir(MyClass)
(,)
“UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU u'、uuu str_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
为什么Python文档中的
\uu mro\uuu
没有与dir()一起列出?:
因为提供dir()主要是为了方便在
交互式提示,它尝试提供一组有趣的名称
不仅仅是试图提供一个严格或一致定义的集合
其详细行为可能会随着版本的不同而变化。对于
例如,当
论点是一个类
\uuuumro\uuuuuu
是一个只读属性,用于在类从多个基类继承时确定方法解析。如果希望自定义此行为,则应使用元类(一种特殊类型的对象,其目的是创建类实例),该元类重写mro()
方法<代码>\uuuMRO\uuuuuuuuuu
在任何情况下都保持不变。我最近也在想同样的事情。我在寻找一个更符合“Python的实现如何导致mro
/\uuuuu mro\uuuuuu
不被列在dir
中?”的答案,而不仅仅是“Python的文档如何证明mro
不被列在dir
中?”我不喜欢当我对编程语言行为的期望与它的实际行为不匹配时,因为这意味着我对该语言的理解是错误的——除非它只是一个类似urllib2.escape
的bug。所以我四处搜寻,直到找到答案
上面评论中引用的文档中的adolfopa行很好地解释了dir的行为
如果对象是类型或类对象,则列表包含其属性的名称,并递归地包含其基的属性的名称
这是什么意思dir
递归地从类的\uuu dict\uuu
及其每个超类的\uu dict\uu
收集属性
(<class '__main__.MyClass'>, <type 'object'>)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
之所以dir(object)
没有列出\uuumro\uuuu
/mro
,是因为它们不是object的属性。它们是类型的属性。每一个没有定义自己的\uuuu元类的类都是类型的实例。大多数元类都是子类type
。此类元类的实例也是类型的实例<代码>MyClass.\uuuMRO\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
Python实现类的方式必然会对dir的工作方式产生轻微的异常
通常,dir(MyClass)==dir(MyClass(*requiredparameters))#True
然而,dir(type)==dir(type(*requiredparameters))#False
,但唯一可能的方法是如果type.uu dict_u
和dir
是相同的。这显然不是dir
的目的
但是等等dir
是通过递归求和创建的,为什么我们不能改变它的最后一部分,使dir(object)
不再只是对象。
而是成为对象。
。这样,它将具有mro
/\uuuuuuuuuuuuuuuuuuuuuu
以及类对象具有的所有其他属性?啊,但是这些将是类对象的属性,而不是类。那么,有什么区别呢
考虑
set(dir(object)) == set(dict(object.__dict__).keys() #True
class A(object):
...
class B(object):
...
class C(B):
...
class D(C,A):
...
set(dir(D)) == set(D.__dict__.keys()) + set(C.__dict__.keys()) \
+ set(B.__dict__.keys()) + set(A.__dict__.keys()) \
+ set(object.__dict__.keys()) #True
list.uu mro_uuu#(,)
鉴于
list.__mro__ #(<type 'list'>, <type 'object'>)
[]。\uuu mro__
#回溯(最近一次呼叫最后一次):
#文件“”,第1行,在
#AttributeError:'list'对象没有属性'\uuuMRO''
现在,我们可以很好地回答我们可以依靠dir
列出什么,以及我们可以依靠dir
不列出什么。简单的答案就是我们已经讨论过的答案。它以递归方式列出类的\uuuuu dict\uuu
中的所有键,以及每个超类的\uuuu dict\uuu
中的所有键。对于一个实例,它还包括该实例的\uuuu dict\uuuu
中的所有参数。要填充负数空间,它不会列出\uuuuuuGetAttr\uuuuuuuuuuu
中定义的任何内容,或者\uuuuuuuuuuGetAttribute\uuuuuuuuuuuuuuuuuuuuuuuuuuuu
中定义的任何内容(如果它不在目录中)。它也没有列出类型/元类型的任何属性
我觉得我应该指出的另一件事是:丹的答案,在我写这篇文章时是公认的答案,包含的信息是不准确的,或者至少是误导性的
无法设置内置对象的属性,因此在某种意义上,type.\uuuumro\uuuuu
是“只读”的,但其方式与list.append
是或type.mro
是相同的
MyClass.\uu mro\uu=“Hello world!”
不会导致错误。它不会影响类型中定义的方法解析顺序。因此,如果您试图修改该行为,它可能不会产生您预期的效果。(它所做的是使MyClass(*requiredparameters)。\uuuumro\uuuu
成为“Hello World!”
,这本应该是您所期望的,因为在python中定义类的属性就是这样工作的。)您还可以在对类型进行子分类以创建元类时重写\umro\uu
。如果您不重写它,它将被继承,就像您不重写的任何其他内容一样。(如果您创建的元类不是类型的子类,也不是返回类型实例的函数,那么您可能已经非常清楚自己在做什么,因此不必担心这一点,但是__<
[].__mro__
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# AttributeError: 'list' object has no attribute '__mro__'