How does Python's super() work with multiple inheritance?

后端 未结 16 2193
孤街浪徒
孤街浪徒 2020-11-21 05:19

I\'m pretty much new in Python object oriented programming and I have trouble understanding the super() function (new style classes) especially when it comes to

相关标签:
16条回答
  • 2020-11-21 05:48

    In python 3.5+ inheritance looks predictable and very nice for me. Please looks at this code:

    class Base(object):
      def foo(self):
        print("    Base(): entering")
        print("    Base(): exiting")
    
    
    class First(Base):
      def foo(self):
        print("   First(): entering Will call Second now")
        super().foo()
        print("   First(): exiting")
    
    
    class Second(Base):
      def foo(self):
        print("  Second(): entering")
        super().foo()
        print("  Second(): exiting")
    
    
    class Third(First, Second):
      def foo(self):
        print(" Third(): entering")
        super().foo()
        print(" Third(): exiting")
    
    
    class Fourth(Third):
      def foo(self):
        print("Fourth(): entering")
        super().foo()
        print("Fourth(): exiting")
    
    Fourth().foo()
    print(Fourth.__mro__)
    

    Outputs:

    Fourth(): entering
     Third(): entering
       First(): entering Will call Second now
      Second(): entering
        Base(): entering
        Base(): exiting
      Second(): exiting
       First(): exiting
     Third(): exiting
    Fourth(): exiting
    (<class '__main__.Fourth'>, <class '__main__.Third'>, <class '__main__.First'>, <class '__main__.Second'>, <class '__main__.Base'>, <class 'object'>)
    

    As you can see, it calls foo exactly ONE time for each inherited chain in the same order as it was inherited. You can get that order by calling .mro :

    Fourth -> Third -> First -> Second -> Base -> object

    0 讨论(0)
  • 2020-11-21 05:49

    This is known as the Diamond Problem, the page has an entry on Python, but in short, Python will call the superclass's methods from left to right.

    0 讨论(0)
  • 2020-11-21 05:50

    Consider calling super().Foo() called from a sub-class. The Method Resolution Order (MRO) method is the order in which method calls are resolved.

    Case 1: Single Inheritance

    In this, super().Foo() will be searched up in the hierarchy and will consider the closest implementation, if found, else raise an Exception. The "is a" relationship will always be True in between any visited sub-class and its super class up in the hierarchy. But this story isn't the same always in Multiple Inheritance.

    Case 2: Multiple Inheritance

    Here, while searching for super().Foo() implementation, every visited class in the hierarchy may or may not have is a relation. Consider following examples:

    class A(object): pass
    class B(object): pass
    class C(A): pass
    class D(A): pass
    class E(C, D): pass
    class F(B): pass
    class G(B): pass
    class H(F, G): pass
    class I(E, H): pass
    

    Here, I is the lowest class in the hierarchy. Hierarchy diagram and MRO for I will be

    (Red numbers showing the MRO)

    MRO is I E C D A H F G B object

    Note that a class X will be visited only if all its sub-classes, which inherit from it, have been visited(i.e., you should never visit a class that has an arrow coming into it from a class below that you have not yet visited).

    Here, note that after visiting class C , D is visited although C and D DO NOT have is a relationship between them(but both have with A). This is where super() differs from single inheritance.

    Consider a slightly more complicated example:

    (Red numbers showing the MRO)

    MRO is I E C H D A F G B object

    In this case we proceed from I to E to C. The next step up would be A, but we have yet to visit D, a subclass of A. We cannot visit D, however, because we have yet to visit H, a subclass of D. The leaves H as the next class to visit. Remember, we attempt to go up in hierarchy, if possible, so we visit its leftmost superclass, D. After D we visit A, but we cannot go up to object because we have yet to visit F, G, and B. These classes, in order, round out the MRO for I.

    Note that no class can appear more than once in MRO.

    This is how super() looks up in the hierarchy of inheritance.

    Credits for resources: Richard L Halterman Fundamentals of Python Programming

    0 讨论(0)
  • 2020-11-21 05:52

    This is to how I solved to issue of having multiple inheritance with different variables for initialization and having multiple MixIns with the same function call. I had to explicitly add variables to passed **kwargs and add a MixIn interface to be an endpoint for super calls.

    Here A is an extendable base class and B and C are MixIn classes both who provide function f. A and B both expect parameter v in their __init__ and C expects w. The function f takes one parameter y. Q inherits from all three classes. MixInF is the mixin interface for B and C.

    • IPython NoteBook Of This Code
    • Github Repo with code example
    
    class A(object):
        def __init__(self, v, *args, **kwargs):
            print "A:init:v[{0}]".format(v)
            kwargs['v']=v
            super(A, self).__init__(*args, **kwargs)
            self.v = v
    
    
    class MixInF(object):
        def __init__(self, *args, **kwargs):
            print "IObject:init"
        def f(self, y):
            print "IObject:y[{0}]".format(y)
    
    
    class B(MixInF):
        def __init__(self, v, *args, **kwargs):
            print "B:init:v[{0}]".format(v)
            kwargs['v']=v
            super(B, self).__init__(*args, **kwargs)
            self.v = v
        def f(self, y):
            print "B:f:v[{0}]:y[{1}]".format(self.v, y)
            super(B, self).f(y)
    
    
    class C(MixInF):
        def __init__(self, w, *args, **kwargs):
            print "C:init:w[{0}]".format(w)
            kwargs['w']=w
            super(C, self).__init__(*args, **kwargs)
            self.w = w
        def f(self, y):
            print "C:f:w[{0}]:y[{1}]".format(self.w, y)
            super(C, self).f(y)
    
    
    class Q(C,B,A):
        def __init__(self, v, w):
            super(Q, self).__init__(v=v, w=w)
        def f(self, y):
            print "Q:f:y[{0}]".format(y)
            super(Q, self).f(y)
    
    0 讨论(0)
提交回复
热议问题