Ваше непонимание видно из этого комментария:
Я не переопределять в LockableDict
__init__
, поэтому он должен генерировать __init__
делать автоматические вызовы базовых классов __init__
с, не так ли?
Нет!
Во-первых, ничто автоматически не генерируется; разрешение метода происходит во время вызова.
И во время разговора Python не будет звонить каждый базовый класс __init__
, он будет вызывать только первый найденный. *
Именно поэтому super
существует. Если вы явно не вызываете super
в переопределении, базовые классы или даже классы sibling не получат их реализации. И dict.__init__
не называет его super
.
Также и ваш Lockable.__init__
. Таким образом, это означает, что изменение ордера гарантирует, что Lockable.__init__
будет вызван ... но dict.__init__
сейчас не вызывается.
Итак, что вы на самом деле хотите сделать? Ну, алгоритм MRO Python разработан, чтобы обеспечить максимальную гибкость для иерархий , взаимодействующих с классами, с любыми не взаимодействующими классами, вставленными в конце. Таким образом, вы можете сделать это:
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, что несколько сложнее, чем можно было ожидать. Это же правило MRO применяется, когда вы вызываете super
, чтобы найти «следующий» класс, который может быть базовым классом, или родным братом, или даже родственным подклассом. Вы можете найти статью Википедии о C3 linearization более доступной.
** Специально для встроенных классов, потому что они особенные в нескольких направлениях, которые не стоит вдаваться сюда. Опять же, многие встроенные классы фактически ничего не делают в своих __init__
и вместо этого выполняют всю инициализацию внутри конструктора __new__
.
Если вы его не называете, это не называется. – laike9m
Что это значит? Я не переопределяю '__init__' в' LockableDict', поэтому он должен генерировать '__init__', делая автоматические вызовы базовым классам' __init__', не так ли? Также он не объясняет, почему работает второй вариант ... – Sventimir
Вы должны явно называть '__init__' в' __init__' LockableDict – RvdK