2015-03-03 1 views
0

Я пытаюсь понять многократное наследование Python, и я вроде понимаю MRO, super() и передает аргументы в MI, но пока я читал приведенный ниже пример это меня смутило.Python Multiple Inheritance: Прохождение аргумента (** kwargs) и super()

class Contact: 
    all_contacts = [] 

    def __init__(self, name=None, email=None, **kwargs): 
     super().__init__(**kwargs) 
     self.name = name 
     self.email = email 
     self.all_contacts.append(self) 


class AddressHolder: 
    def __init__(self, street=None, city=None, state=None, code=None, **kwargs): 
     super().__init__(**kwargs) 
     self.street = street 
     self.city = city 
     self.state = state 
     self.code = code 


class Friend(Contact, AddressHolder): 
    def __init__(self, phone='', **kwargs): 
     super().__init__(**kwargs) 
     self.phone = phone 

Теперь, что я не понимаю, поэтому используйте super() в классе Contact и AddressHolder. Я имею в виду, что super() используется, когда мы наследуем родительский класс, но оба контакта & AddressHolder не наследуются ни от какого другого класса. (технически они наследуются от object). Этот пример меня смущает правильным использованием супер()

+0

afaik он называет следующий пункт в стеке MRO .... –

ответ

8

Все классы (новый стиль) имеют линеаризованный порядок разрешения метода (MRO). В зависимости от дерева наследования, фактически вычисление MRO может быть немного разумом, но оно детерминировано через relatively simple algorithm. super получает делегата на следующий класс в MRO. В вашем примере, Friend имеет следующий MRO:

Friend -> Contact -> AddressHolder -> object 

Если вы звоните супер в на из Friend «методов s, вы получите доверитель, что делегаты Contact» s методы. Если этот метод не вызывает super, вы никогда не будете называть методы на AddressHolder. Другими словами, super отвечает за вызов только следующего метода в MRO, а не ALL остальных методов в MRO.


Это все хорошо, так как object имеет полностью функциональный __init__ метод (так долго, как **kwargs пусто в этой точке). К сожалению, он не работает, если вы пытаетесь разрешить цепочку вызовов какого-либо настраиваемого метода. например foo. В этом случае вы хотите вставить базовый класс, на который наследуются все базовые классы. Поскольку этот класс является базой для всех классов (или, по крайней мере, базовых классов) для наследования. Этот класс будет в конечном итоге в конце MRO и может сделать параметр проверки :

class FooProvider: 
    def foo(self, **kwargs): 
     assert not kwargs # Make sure all kwargs have been stripped 

class Bar(FooProvider): 
    def foo(self, x, **kwargs): 
     self.x = x 
     super().foo(**kwargs) 

class Baz(FooProvider): 
    def foo(self, y, **kwargs): 
     self.y = y 
     super().foo(**kwargs) 

class Qux(Bar, Baz): 
    def foo(self, z, **kwargs): 
     self.z = z 
     super().foo(**kwargs)  

демо:

>>> q = Qux() 
>>> q.foo(x=1, y=2, z=3) 
>>> vars(q) 
{'z': 3, 'y': 2, 'x': 1} 
>>> q.foo(die='invalid') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: foo() missing 1 required positional argument: 'z' 
>>> 
>>> q.foo(x=1, y=2, z=3, die='invalid') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/usr/local/google/home/mgilson/sandbox/super_.py", line 18, in foo 
    super().foo(**kwargs) 
    File "/usr/local/google/home/mgilson/sandbox/super_.py", line 8, in foo 
    super().foo(**kwargs) 
    File "/usr/local/google/home/mgilson/sandbox/super_.py", line 13, in foo 
    super().foo(**kwargs) 
    File "/usr/local/google/home/mgilson/sandbox/super_.py", line 3, in foo 
    assert not kwargs # Make sure all kwargs have been stripped 
AssertionError 

Обратите внимание, вы все равно можете иметь аргументы по умолчанию с этим подходом, чтобы вы дон Там слишком много.

Заметим, что это не единственная стратегия, чтобы справиться с этой проблемой - Есть и другие подходы, которые можно предпринять при принятии Примеси, и т.д., но это, безусловно, самый надежный подход.

+0

Большое спасибо @mgilson за такое приятное объяснение. Теперь это имеет большой смысл. –