如果定义一个没有 __init__ 方法的 class 会怎样?
What happens if define a class without __init__ method?
假设我定义了四个类如下:
(该代码已在 Python 3.6.5 上进行了 测试。不过,我预计它 也应该适用于 Python 2.7.x 与 from __future__ import print_function
)
In [1]: class A(object):
...: pass
...:
...: class B(object):
...: def __init__(self, value):
...: print('B(value=%s)' % value)
...:
...: class C(A):
...: def __init__(self, value):
...: print('C(value=%s)' % value)
...: super(C, self).__init__(value)
...:
...: class D(A, B):
...: def __init__(self, value):
...: print('D(value=%s)' % value)
...: super(D, self).__init__(value)
...:
In [2]: C.mro()
Out[2]: [__main__.C, __main__.A, object]
In [3]: D.mro()
Out[3]: [__main__.D, __main__.A, __main__.B, object]
注意两点:
class A
没有 __init__
方法;
根据mro,C和D都有相同的继任者A
信息。
所以我想super(C, self).__init__(value)
和super(D, self).__init__(value)
都会触发A
中定义的__init__
方法。
然而,下面的结果让我很困惑!
In [4]: C(0)
C(value=0)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-4-75d9b7f7d447> in <module>()
----> 1 C(0)
<ipython-input-1-5252938615c6> in __init__(self, value)
9 def __init__(self, value):
10 print('C(value=%s)' % value)
---> 11 super(C, self).__init__(value)
12
13 class D(A, B):
TypeError: object.__init__() takes no parameters
In [5]: D(1)
D(value=1)
B(value=1)
Out[5]: <__main__.D at 0x2a6e8755b70
可以看到class D
初始化成功,class C
初始化失败
是什么导致 class C
和 class D
之间的不同行为?
EDIT 我不认为我的问题是关于 mro(实际上我或多或少知道 mro 关于 python),我的问题是关于不同的__init___
方法的行为。
EDIT2我傻了,是关于mro的。
感谢您的帮助。
Class A
没有单独的 __init__
方法 - 它是通过 A
自己的 mro
.
>>> A.__init__ is object.__init__
True
Class B 有一个单独的 __init__
方法 - 它不需要遍历 mro
.
>>> B.__init__ is object.__init__
False
注意区别是拥有和继承__init__
。仅仅因为可以提供 A.__init__
并不意味着 A
本身就有一个 __init__
方法。
当 C 查找其 super().__init__
时,将尝试以下操作:
C.__init__
被跳过
A.__init__
不存在
object.__init__
存在并被调用
当 D 查找其 super().__init__
时,将尝试以下操作:
D.__init__
被跳过
A.__init__
不存在
B.__init__
存在并被调用
object.__init__
从未被查找过
这个区别是使用 super
而不是显式基础 class 的一个主要点。它允许将专门的 classes 插入层次结构 (example)。
此行为的原因是 python 中属性查找的工作方式。当您访问 A.__init__
时,python 在内部遍历 A
的 MRO,直到找到 定义 和 [=14= 的 class ] 属性。 在此查找期间忽略继承的属性。
当您在 C.__init__
中调用 super(C, self).__init__(value)
时,python 遍历 MRO [A, object]
直到找到 __init__
属性。重要的是 A
确实 而不是 定义了 __init__
属性,因此查找从 A
到 object
和 returns object.__init__
.
同样的事情发生在D.__init__
,除了在这种情况下被遍历的MRO是[A, B, object]
。同样,A
没有定义 __init__
,因此查找继续并且 returns B.__init__
.
作为实验,您可以更改 A
的定义以定义 __init__
,如下所示:
class A(object):
__init__ = object.__init__
你会注意到实例化 D
现在会抛出与 C
:
相同的错误
>>> D(3)
D(value=3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "untitled.py", line 17, in __init__
super(D, self).__init__(value)
TypeError: object.__init__() takes no parameters
假设我定义了四个类如下:
(该代码已在 Python 3.6.5 上进行了 测试。不过,我预计它 也应该适用于 Python 2.7.x 与 from __future__ import print_function
)
In [1]: class A(object):
...: pass
...:
...: class B(object):
...: def __init__(self, value):
...: print('B(value=%s)' % value)
...:
...: class C(A):
...: def __init__(self, value):
...: print('C(value=%s)' % value)
...: super(C, self).__init__(value)
...:
...: class D(A, B):
...: def __init__(self, value):
...: print('D(value=%s)' % value)
...: super(D, self).__init__(value)
...:
In [2]: C.mro()
Out[2]: [__main__.C, __main__.A, object]
In [3]: D.mro()
Out[3]: [__main__.D, __main__.A, __main__.B, object]
注意两点:
class A
没有__init__
方法;根据mro,C和D都有相同的继任者
A
信息。
所以我想super(C, self).__init__(value)
和super(D, self).__init__(value)
都会触发A
中定义的__init__
方法。
然而,下面的结果让我很困惑!
In [4]: C(0)
C(value=0)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-4-75d9b7f7d447> in <module>()
----> 1 C(0)
<ipython-input-1-5252938615c6> in __init__(self, value)
9 def __init__(self, value):
10 print('C(value=%s)' % value)
---> 11 super(C, self).__init__(value)
12
13 class D(A, B):
TypeError: object.__init__() takes no parameters
In [5]: D(1)
D(value=1)
B(value=1)
Out[5]: <__main__.D at 0x2a6e8755b70
可以看到class D
初始化成功,class C
初始化失败
是什么导致 class C
和 class D
之间的不同行为?
EDIT 我不认为我的问题是关于 mro(实际上我或多或少知道 mro 关于 python),我的问题是关于不同的__init___
方法的行为。
EDIT2我傻了,是关于mro的。
感谢您的帮助。
Class
A
没有单独的__init__
方法 - 它是通过A
自己的mro
.>>> A.__init__ is object.__init__ True
Class B 有一个单独的
__init__
方法 - 它不需要遍历mro
.>>> B.__init__ is object.__init__ False
注意区别是拥有和继承__init__
。仅仅因为可以提供 A.__init__
并不意味着 A
本身就有一个 __init__
方法。
当 C 查找其
super().__init__
时,将尝试以下操作:C.__init__
被跳过A.__init__
不存在object.__init__
存在并被调用
当 D 查找其
super().__init__
时,将尝试以下操作:D.__init__
被跳过A.__init__
不存在B.__init__
存在并被调用object.__init__
从未被查找过
这个区别是使用 super
而不是显式基础 class 的一个主要点。它允许将专门的 classes 插入层次结构 (example)。
此行为的原因是 python 中属性查找的工作方式。当您访问 A.__init__
时,python 在内部遍历 A
的 MRO,直到找到 定义 和 [=14= 的 class ] 属性。 在此查找期间忽略继承的属性。
当您在 C.__init__
中调用 super(C, self).__init__(value)
时,python 遍历 MRO [A, object]
直到找到 __init__
属性。重要的是 A
确实 而不是 定义了 __init__
属性,因此查找从 A
到 object
和 returns object.__init__
.
同样的事情发生在D.__init__
,除了在这种情况下被遍历的MRO是[A, B, object]
。同样,A
没有定义 __init__
,因此查找继续并且 returns B.__init__
.
作为实验,您可以更改 A
的定义以定义 __init__
,如下所示:
class A(object):
__init__ = object.__init__
你会注意到实例化 D
现在会抛出与 C
:
>>> D(3)
D(value=3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "untitled.py", line 17, in __init__
super(D, self).__init__(value)
TypeError: object.__init__() takes no parameters