2016-09-09 3 views
0

Редактировать: Я нахожусь на Python 3.Python - Вызов __init__ для нескольких родительских классов

У меня есть класс, который расширяет X как Y и Z:

class X(Y, Z): 
    def __init__(self): 
    # Call Y's __init__ 
    # Call Z's __init 
    pass 

Мне нужно позвонить __init__ как на Y и Z из __init__ на X. Какой был бы лучший способ сделать это?

+0

Это Python 2 или 3? – DeepSpace

+0

Я нахожусь на Python 3. – masnun

+0

Это еще одна причина, почему множественное наследование - это плохо, так как вы можете спросить о лучших практиках в такой плохой практике? – Sergius

ответ

2

Это полностью зависит от того, Y и Z были разработаны работать совместно с множественным наследованием. Если они есть, то вы должны быть в состоянии использовать только super:

class X(Y, Z): 
    def __init__(self): 
     super().__init__() 

Когда я говорю, что Y и Z должны быть разработаны для совместной работы с множественным наследованием, я имею в виду, что они должны также вызвать супер в их __init__ методы:

class Y: 
    def __init__(self): 
     print('Y.__init__') 
     super().__init__() 

class Z: 
    def __init__(self): 
     print('Z.__init__') 
     super().__init__() 

они также должны иметь определенную стратегию для обработки различных аргументов, так как (в частности, конструктор) класса часто различаются, в которых ключевое слово аргументы, которые они принимают. На данный момент стоит прочитать Super considered super! и Super considered harmful, чтобы понять некоторые распространенные идиомы и подводные камни относительно супер.

Если вы не знаете, были ли Y и Z предназначены для совместного множественного наследования, то самым безопасным средством правовой защиты является то, что они не были.


Если классы не предназначены для работы с кооперативным множественным наследованием, то вам необходимо начать легко ступая (вы в опасных водах). Вы можете созвонимся __init__ индивидуально:

class X(Y, Z): 
    def __init__(self): 
     Y.__init__(self) 
     Z.__init__(self) 

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

+0

В моем случае родители - 'threading.Thread' и' logging.Handler' - как я могу проверить, созданы ли они для совместной работы при множественном наследовании? – masnun

+1

Насколько я могу судить, ['threading.Thread'] (https://hg.python.org/cpython/file/tip/Lib/threading.py#l738) нет. – mgilson

+0

@masnun Вопрос, который вам нужно задать самому себе: почему вы хотите унаследовать их обоих? Вы смешиваете несвязанные понятия. Было бы чище использовать класс с обоими из них как поля (или некоторые другие чистые шаблоны). – freakish

2

Как правило, нет другого способа позвонить по телефону Y.__init__(self) и Z.__init__(self). Это единственный способ гарантировать, что оба конструктора называются не реже одного раза.

Однако в некоторых странных (или нормальных, в зависимости от того, как вы смотрите на это) случаях это может привести к очень неинтуитивным результатам, в которых называются базовые Конструкторы несколько раз:

class Y: 
    def __init__(self): 
     print('Y') 
     super().__init__() 

class Z: 
    def __init__(self): 
     print('Z') 
     super().__init__() 

class X(Y, Z): 
    def __init__(self): 
     print('X') 
     Y.__init__(self) 
     Z.__init__(self) 

X() 

Результатов в

X 
Y 
Z 
Z 

В таком случае super().__init__() в X (вместо звонков .__init__()) кажется естественным и будет работать правильно.Однако он не сработает, если Y и Z не вызывают super().__init__(). В этом случае вы вызываете только один из конструкторов.

Как правило, нет возможности правильно решить вашу проблему, не зная реализации базовых классов.

YARtAMI = Еще одна причина, чтобы избежать множественное наследование

+0

Спасибо за подробное объяснение. В моем случае ни один из родительских классов не имеет общего предка. – masnun

+0

@masnun Им не обязательно иметь. Я обновил ответ. – freakish

+0

Есть ли объяснение для понимания того, почему первый вызов 'super() .__ init __()' в Y запускает Z .__ init __() ??? Я понял, что Y и Z наследуются от 'object', поэтому я не могу понять, почему первая« Z »печать на экране – madtyn

Смежные вопросы