2016-01-19 3 views
14

Рассмотрим следующий фрагмент кода Pythonпитона множественное наследование передать аргументы конструкторам, используя супер

class A(object): 
    def __init__(self, a): 
     self.a = a 

class B(A): 
    def __init__(self, a, b): 
     super(B, self).__init__(a) 
     self.b = b 

class C(A): 
    def __init__(self, a, c): 
     super(C, self).__init__(a) 
     self.c = c 

class D(B, C): 
    def __init__(self, a, b, c, d): 
     #super(D,self).__init__(a, b, c) ??? 
     self.d = d 

Мне интересно, как я могу передать a, b и c конструкторам, соответствующих базовых классов.

Спасибо,

+5

Возможный дубликат [Как работает супер() Python с множественным наследованием?] (Http://stackoverflow.com/questions/3277367/how-does-pythons-super-work-with-multiple-inheritance) – erip

+0

вы может дважды вызывать '__init__' для' B' и 'C'. – sobolevn

+0

Но тогда 'A .__ init__' будет вызываться дважды, не так ли? – user5459381

ответ

22

Ну, если вы имеете дело с множественным наследованием в целом, ваши базовые классы (к сожалению) должны быть , предназначенные для множественного наследования. Классы B и C в вашем примере нет, и поэтому вы не смогли найти подходящий способ применения super в D.

Одним из распространенных способов разработки ваших базовых классов для множественного наследования, является для базовых среднего уровня классов, чтобы принять дополнительные аргументы в их методе __init__, что они не намерены использовать и передавать их на их super вызов.

Вот один из способов сделать это в Python:

class A(object): 
    def __init__(self,a): 
     self.a=a 

class B(A): 
    def __init__(self,b,**kw): 
     self.b=b 
     super(B,self).__init__(**kw) 

class C(A): 
    def __init__(self,c,**kw): 
     self.c=c 
     super(C,self).__init__(**kw) 

class D(B,C): 
    def __init__(self,a,b,c,d): 
     super(D,self).__init__(a=a,b=b,c=c) 
     self.d=d 

Это можно рассматривать как разочарование, но это только так оно и есть.

+1

Вам не нужно писать 'kw.pop ('something')', вы можете просто взять 'something' в качестве аргумента. – GingerPlusPlus

+0

@GingerPlusPlus правый! исправлено, спасибо. (Я начал писать его с позиции args в виду, затем переключился на kwargs ...) – shx2

+1

Спасибо, shx2, приятное решение! – Ling

3

К сожалению, нет никакого способа, чтобы сделать эту работу, используя super() без изменения базовых классов. Любой вызов конструкторов для B или C собирается попробовать и вызвать следующий класс в Method Resolution Order, который всегда будет B или C вместо A класса, что класс конструкторы B и C предположить.

Альтернативой является вызов конструкторов явно без использования super() в каждом классе.

class A(object): 
    def __init__(self, a): 
     object.__init__() 
     self.a = a 

class B(A): 
    def __init__(self, a, b): 
     A.__init__(self, a) 
     self.b = b 

class C(object): 
    def __init__(self, a, c): 
     A.__init__(self, a) 
     self.c = c 

class D(B, C): 
    def __init__(self, a, b, c, d): 
     B.__init__(self, a, b) 
     C.__init__(self, a, c) 
     self.d = d 

Существует еще недостаток здесь, как A конструктор будет вызван дважды, что на самом деле не имеет большого влияния в этом примере, но может вызвать проблемы в более сложных конструкторах. Вы можете включить проверку, чтобы предотвратить запуск конструктора более одного раза.

class A(object): 
    def __init__(self, a): 
     if hasattr(self, 'a'): 
      return 
     # Normal constructor. 

Некоторые называют бы это недостатком super(), и это в каком-то смысле, но это также просто недостаток множественного наследования в целом. Модели наследования алмазов часто подвержены ошибкам. И многие обходные пути для них приводят к еще более запутанному и подверженному ошибкам коду. Иногда лучший ответ - попытаться реорганизовать ваш код, чтобы использовать меньшее количество наследований.