简体   繁体   中英

Python Multiple Inheritance: Argument passing (**kwargs) and super()

I am trying to understand Python multiple inheritance and I kind of understand MRO, super() and passing arguments in MI, but while I was reading the below example it kind of confused me.

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

Now what I fail to understand is why use super() in Contact and AddressHolder class. I mean super() is used when we are inheriting from a parent class but both Contact & AddressHolder are not inheriting from any other class. (technically they are inheriting from object ). This example confuses me with the right use of super()

All (new style) classes have a linearized method resolution order (MRO). Depending on the inheritance tree, actually figuring out the MRO can be a bit mind-bending, but it is deterministic via a relatively simple algorithm . You can also check the MRO through a class's __mro__ attribute.

super gets a delegator to the next class in the MRO. In your example, Friend has the following MRO:

Friend -> Contact -> AddressHolder -> object

If you call super in one of Friend 's methods, you'll get a delegator that delegates to Contact 's methods. If that method doesn't call super , you'll never call the methods on AddressHolder . In other words, super is responsible for calling only the next method in the MRO, not ALL the remaining methods in the MRO.

(If you call super in one of Friend 's methods and Contact doesn't have its own implementation of that method, then super will delegate to AddressHolder , or whichever class has the next implementation for that method in the MRO.)


This is all well and good since object has a completely functional __init__ method (so long as **kwargs is empty at that point). Unfortunately, it doesn't work if you are trying to resolve the call chain of some custom method. eg foo . In that case, you want to insert a base class that all of the base classes inherit from. Since that class is a base for all of the classes (or at least base classes) to inherit from. That class will end up at the end of the MRO and can do parameter validation 1 :

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)     

demo:

>>> 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

Note, you can still have default arguments with this approach so you don't lose too much there.

1 Note, this isn't the only strategy to deal with this problem -- There are other approaches you can take when making mixins, etc. but this is by far the most robust approach.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM