Как я могу заставить конструктор AB вызвать конструкторы для A и B с соответствующими аргументами?
но это дает мне ошибку.
Ответ 2
Другие ответы предложили добавить 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
класс содержит порядок, в котором должны быть вызваны конструкторы и инициализаторы:
>>> AB.__mro__
(<class '__main__.AB'>, <class '__main__.B'>, <class '__main__.A'>, <type 'object'>)
Смотрите, что вызывается первый AB
__init__
, затем B
's, затем A
' s, а затем 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,...)
и т.д., так как это может привести к проблемам позже. Прочтите это для дополнительной информации.
Итак, если вы придерживаетесь super
, тогда возникает проблема. __init__
методы в ваших классах ожидают разные параметры. И вы не можете точно знать порядок, в котором super
будет вызывать методы в этих классах. Порядок определяется алгоритмом C3 во время создания класса. В подклассах другие классы могут проходить между цепочкой вызовов. Таким образом, вы не можете иметь разные параметры в __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
.
Использование или отсутствие делегирования зависит от вашего дела, которое не ясно из вашего вопроса. Но это может быть вариант для рассмотрения.