2013-08-01 3 views
11
class A(): 
    def __init__(self, x, y): 
     self.x = x 
     self.y = y 

class B(): 
    def __init__(self, z=0): 
     self.z = z 

class AB(A,B): 
    def __init__(self, x, y, z=0): 
     ? 

Как я могу заставить конструктор AB вызвать конструкторы для A и B с соответствующими аргументами?Вызов конструкторов суперкласса в python с различными аргументами

Я попытался

class AB(A,B): 
    def __init__(self, x, y, z=0): 
     A.__init__(x,y) 
     B.__init__(z) 

, но это дает мне ошибку.

+1

Почему вместо делегирования вы используете наследование? Потому что случай множественного наследования должен обрабатываться с помощью 'super', который не будет работать из-за разных параметров в' __init__'. – ovgolovin

+2

@ovgolovin Потому что я неопытный программист. Я не знаю, что такое делегация. Я постараюсь разобраться в этом. –

+0

@ovgolovin Спасибо. Оказалось, что я решил проблему с оберткой. –

ответ

11

Вы не прошли self.

class AB(A, B): 
    def __init__(self, x, y, z=0): 
     A.__init__(self, x, y) 
     B.__init__(self, z) 

Обратите внимание, что если эта иерархия наследования становится все более сложным, вы столкнетесь с проблемами с конструкторами не выполняет или получения перезапущена. Посмотрите на superproblems с super), и не забудьте наследовать от object, если вы на 2.x, и ваш класс не наследует ни от чего другого.

+0

Аг, так тупой. Спасибо. –

10

Другие ответы предложили добавить 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.

Использование или отсутствие делегирования зависит от вашего дела, которое неясно из вашего вопроса. Но это может быть вариант рассмотрения.