请考虑以下代码:
class Lockable(object):
def __init__(self):
self._lock = None
def is_locked(self):
return self._lock is None
class LockableDict(dict, Lockable):
pass
现在:
In [2]: l = example.LockableDict(a=1, b=2, c=3)
In [3]: l.is_locked()
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-3-4344e3948b9c> in <module>()
----> 1 l.is_locked()
/home/sven/utils/example.py in is_locked(self)
8
9 def is_locked(self):
---> 10 return self._lock is None
AttributeError: 'LockableDict' object has no attribute '_lock'
看起来Lockable.__init__
根本没有被调用。是这样吗?为什么呢?
为了让事情变得更有趣,事实证明,改变LockableDict类标题就足够了:
class LockableDict(Lockable, dict):
让它发挥作用。为什么呢?
答案 0 :(得分:4)
您的误解在此评论中很清楚:
我不会覆盖
__init__
中的LockableDict
,因此它应生成__init__
自动调用基类&#39}。__init__
s,不应该吗?
没有!
首先,没有任何东西自动生成;方法解析在呼叫时发生。
在通话时,Python不会调用每个基类的__init__
,它只会调用它找到的第一个 * < / SUP>
这就是super
存在的原因。如果你没有在覆盖中显式调用super
,那么基类甚至兄弟类都不会调用它们的实现。而dict.__init__
并未调用其super
。
你的Lockable.__init__
也没有。因此,这意味着撤消订单会确保调用Lockable.__init__
...但dict.__init__
现在不会被调用
那么,你真的想做什么?好吧,Python的MRO算法旨在为合作类的层次结构提供最大的灵活性,最后抛出任何非合作类。所以,你可以这样做:
class Lockable(object):
def __init__(self):
super().__init__() # super(Lockable, self).__init__() for 2.x
self._lock = None
def is_locked(self):
return self._lock is None
class LockableDict(Lockable, dict):
pass
另请注意,这允许您通过所有合作类在链中传递初始化参数,然后使用您知道它需要的参数调用不友好的类__init__
。
在少数情况下,你必须先安排一个不友好的课程。 ** 在这种情况下,你必须明确地打电话给他们:
class LockableDict(dict, Lockable):
def __init__(self):
dict.__init__(self)
Lockable.__init__(self)
但幸运的是,这并不经常出现。
*在标准method resolution order中,这比您预期的要复杂一些。当您致电super
以找到&#34; next&#34;时,会应用相同的MRO规则。 class - 可以是基类,兄弟,甚至是子类的兄弟。您可能会发现C3 linearization上的维基百科文章更加平易近人。
**特别是对于内置课程,因为他们在某些方面并不特别值得进入这里。然后,许多内置类实际上并没有在__init__
中执行任何操作,而是在__new__
构造函数中进行所有初始化。