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

后端 未结 16 2158
孤街浪徒
孤街浪徒 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

    I wanted to elaborate the answer by lifeless a bit because when I started reading about how to use super() in a multiple inheritance hierarchy in Python, I did't get it immediately.

    What you need to understand is that super(MyClass, self).__init__() provides the next __init__ method according to the used Method Resolution Ordering (MRO) algorithm in the context of the complete inheritance hierarchy.

    This last part is crucial to understand. Let's consider the example again:

    #!/usr/bin/env python2
    
    class First(object):
      def __init__(self):
        print "First(): entering"
        super(First, self).__init__()
        print "First(): exiting"
    
    class Second(object):
      def __init__(self):
        print "Second(): entering"
        super(Second, self).__init__()
        print "Second(): exiting"
    
    class Third(First, Second):
      def __init__(self):
        print "Third(): entering"
        super(Third, self).__init__()
        print "Third(): exiting"
    

    According to this article about Method Resolution Order by Guido van Rossum, the order to resolve __init__ is calculated (before Python 2.3) using a "depth-first left-to-right traversal" :

    Third --> First --> object --> Second --> object
    

    After removing all duplicates, except for the last one, we get :

    Third --> First --> Second --> object
    

    So, lets follow what happens when we instantiate an instance of the Third class, e.g. x = Third().

    1. According to MRO Third.__init__ executes.
      • prints Third(): entering
      • then super(Third, self).__init__() executes and MRO returns First.__init__ which is called.
    2. First.__init__ executes.
      • prints First(): entering
      • then super(First, self).__init__() executes and MRO returns Second.__init__ which is called.
    3. Second.__init__ executes.
      • prints Second(): entering
      • then super(Second, self).__init__() executes and MRO returns object.__init__ which is called.
    4. object.__init__ executes (no print statements in the code there)
    5. execution goes back to Second.__init__ which then prints Second(): exiting
    6. execution goes back to First.__init__ which then prints First(): exiting
    7. execution goes back to Third.__init__ which then prints Third(): exiting

    This details out why instantiating Third() results in to :

    Third(): entering
    First(): entering
    Second(): entering
    Second(): exiting
    First(): exiting
    Third(): exiting
    

    The MRO algorithm has been improved from Python 2.3 onwards to work well in complex cases, but I guess that using the "depth-first left-to-right traversal" + "removing duplicates expect for the last" still works in most cases (please comment if this is not the case). Be sure to read the blog post by Guido!

提交回复
热议问题