Другие ответы предложили добавить self
к первому параметру.
Но обычно выписки из __init__
в родительских классах производятся по super
.
Рассмотрим следующий пример:
class A(object):
def __init__(self, x):
print('__init__ is called in A')
self.x = x
class B(object):
def __init__(self, *args, **kwargs):
print('__init__ is called in B')
super(B, self).__init__(*args, **kwargs)
class AB(B, A):
def __init__(self, *args, **kwargs):
print('__init__ is called in AB')
super(AB, self).__init__(*args, **kwargs)
AB
класс содержит порядок, в котором конструкторы и initializators следует назвать:
>>> AB.__mro__
(<class '__main__.AB'>, <class '__main__.B'>, <class '__main__.A'>, <type 'object'>)
Посмотреть, что первый AB
's __init__
вызывается, то B
' s, затем A
, а затем object
.
Давайте проверим:
>>> ab = AB(1)
__init__ is called in AB
__init__ is called in B
__init__ is called in A
Но эти звонки через эту цепочку сделаны super
. Когда мы вводим super(AB, self)
, это означает: найдите следующий класс после AB
в __mro__
цепочке self
.
Тогда мы должны вызвать super
в B
, ищет следующий класс в цепочке после B
: super(B, self)
.
Важно использовать super
и не звонить вручную A.__init__(self,...)
и т. Д., Так как это может привести к проблемам позже. Read this for more info.
Итак, если вы придерживаетесь super
, то есть проблема. __init__
методы в ваших классах ожидают различные параметры. И вы не можете точно знать порядок, в котором super
будет ссылаться на методы в этих классах. Порядок определяется C3 algorithm во время создания класса. В подклассах другие классы могут проходить между цепочкой вызовов. Таким образом, вы не можете иметь разные параметры в __init__
, так как в этом случае вам всегда нужно будет рассмотреть всю цепочку наследования, чтобы понять, как будут вызваны методы __init__
.
Например, рассмотрите возможность добавления C(A)
и D(B)
классов и CD
подкласса из них. Затем A
больше не будет вызываться после B
, но после C
.
class A(object):
def __init__(self, *args, **kwargs):
print('__init__ is called in A')
super(A, self).__init__(*args, **kwargs)
class B(object):
def __init__(self, *args, **kwargs):
print('__init__ is called in B')
super(B, self).__init__(*args, **kwargs)
class AB(B,A):
def __init__(self, *args, **kwargs):
print('__init__ is called in AB')
super(AB, self).__init__(*args, **kwargs)
class C(A):
def __init__(self, *args, **kwargs):
print('__init__ is called in C')
super(C, self).__init__(*args, **kwargs)
class D(B):
def __init__(self, *args, **kwargs):
print('__init__ is called in D')
super(D, self).__init__(*args, **kwargs)
class CD(D,C):
def __init__(self, *args, **kwargs):
print('__init__ is called in CD')
super(CD, self).__init__(*args, **kwargs)
class ABCD(CD,AB):
def __init__(self, *args, **kwargs):
print('__init__ is called in ABCD')
super(ABCD, self).__init__(*args, **kwargs)
>>> abcd = ABCD()
__init__ is called in ABCD
__init__ is called in CD
__init__ is called in D
__init__ is called in AB
__init__ is called in B
__init__ is called in C
__init__ is called in A
Так что я думаю, что это хорошая идея, чтобы думать об использовании delegation
вместо наследования здесь.
class AB(object):
def __init__(self, x, y, z=0):
self.a = A(x,y)
self.b = B(z)
Таким образом, вы просто создать a
и b
экземпляры A
и B
классов внутри AB
объекта. А затем они могут использовать их, как вам нужно, с помощью методов, ссылаясь на self.a
и self.b
.
Использование или отсутствие делегирования зависит от вашего дела, которое неясно из вашего вопроса. Но это может быть вариант рассмотрения.
Почему вместо делегирования вы используете наследование? Потому что случай множественного наследования должен обрабатываться с помощью 'super', который не будет работать из-за разных параметров в' __init__'. – ovgolovin
@ovgolovin Потому что я неопытный программист. Я не знаю, что такое делегация. Я постараюсь разобраться в этом. –
@ovgolovin Спасибо. Оказалось, что я решил проблему с оберткой. –