Python multiple inheritance of diamond problems

Source: Internet
Author: User

Below, we've got a friend class that inherits from the contact class.

classcontactlist (list):defSearch (self, name):" "Return All contacts this contain the search value in their name." "matching_contacts= []         forContactinchSelf :ifNameinchcontact.name:matching_contacts.append (Contact)returnmatching_contactsclasscontact:all_contacts=contactlist ()def __init__(self, Name, email): Self.name=name Self.email=email Contact.all_contacts.append (self)classFriend (Contact):" "by Super Get an instance of the parent class object, and call the object's __init__ method, pass it to its expected parameters, and then this class did its own initialization, that is, set the phone property" "    def __init__(self, name, email, phone): Super ().__init__(name, email) self.phone= Phone

If you want to add an address to the friend class, address information includes street, city, country, etc. We can pass these strings directly to the __init__ method in friend, or we can put these strings in a tuple or dictionary, and then pass him as a single parameter to the __init__ method.

Another way is to create a new address class that specifically includes these strings, and pass an instance of the class to the __init__ method of the friend class. The advantage of this is that the address class is reused in other buildings, businesses, and organizations.

class Addressholder:     def __init__ (self, street, city, State, code):         = Street         = City        = state = code        

Now the question is, how to add an address to the already existing friend class that inherits from the contact class.

The best approach is multiple inheritance, but then there are two __init__ methods of the parent class that need to be initialized, and they are initialized with different parameters, how do they do it? Let's start with a naïve way of rewriting a friend of the above code:

class Friend (Contact, Addressholder):     def __init__ (self, name, e-mail, phone, street, city, State, code):        Contact. __init__ (self, name, email)        Addressholder. __init__ (self, street, city, State, code)         = Phone        

The above is technically possible, but there are some problems.

First, if we ignore the explicit invocation of the initialization function, it may cause a superclass to not be initialized. It is not obvious here, but in other scenarios it can cause a program to crash, such as inserting data into an disconnected database.

Second, because of the hierarchical results of these classes, it is possible to cause a superclass to be called multiple times. As shown in.

From this, the __init__ in friend first invokes the __init__ in contact, and the privacy initializes object (all classes inherit from Object). Friend then calls Addressholder's __init__ again, implicitly initializing the object superclass, and the parent class is created two times. In our case, it is harmless, but in some scenarios it can be disastrous. (Each method's call order can be modified by __mro__, here slightly)

Looking at the following example, we have a base class that has a Call_me method with two subclasses overriding this method, and the 3rd class extends two methods through multiple inheritance. This is called Diamond inheritance .

Technically, all the multiple inheritance in Python3 is a diamond inheritance, because all classes inherit from object, and the object.__init__ is also a diamond problem. Convert to code as follows:

classBaseclass:num_base_calls=0defCall_me (self):Print("calling method on Base Class") Self.num_base_calls+ = 1class Leftsubclass (baseclass): num_left_calls=0defCall_me (self): Baseclass.call_me (self) Print("calling method on Lef subclass") Self.num_left_calls+ = 1class Rightsubclass (baseclass): num_right_calls=0defCall_me (self): Baseclass.call_me (self) Print("calling method on right subclass") Self.num_right_calls+ = 1class Subclass (Leftsubclass, Rightsubclass): num_sub_calls=0defCall_me (self): Leftsubclass.call_me (self)rightsubclass.call_me (          self)Print("calling method on Subcalss") Self.num_sub_calls+ = 1

Call and get the following output:

$ python->>> s = subclass ()>>> S.call_me () calling method on Base classcalling me Thod on Lef subclasscalling method on Base classcalling method on right subclasscalling method on Subcalssprint
    (S.num_sub_calls, S.num_left_calls, ... s.num_right_calls, s.num_base_calls)1 1 1 2

The call_me of the base class was called two times. But this is not what we want, if you do the actual work, this will lead to very serious bugs, such as bank deposits deposited two times.

For multiple inheritance, we only want to invoke the "next" method instead of the parent class's method. In fact, the next method may not belong to the current class or the parent or ancestor class of the current class. The keyword super solves this problem by following the code rewrite:

classBaseclass:num_base_calls=0defCall_me (self):Print("calling method on Base Class") Self.num_base_calls+ = 1classLeftsubclass (baseclass): Num_left_calls=0defCall_me (self): super (). Call_me () Print("calling method on Lef subclass") Self.num_left_calls+ = 1classRightsubclass (baseclass): Num_right_calls=0defCall_me (self): super (). Call_me () Print("calling method on right subclass") Self.num_right_calls+ = 1classSubclass (Leftsubclass, Rightsubclass): Num_sub_calls=0defCall_me (self): super (). Call_me () Print("calling method on Subcalss") Self.num_sub_calls+ = 1

The results of the implementation are as follows:

>>> s = subclass ()>>> S.call_me () calling method on Base classcalling method in right Subcla Sscalling method on Lef subclasscalling method on Subcalssprint(s.num_sub_calls, S.num_left_calls, ... s.num_right_calls, s.num_base_calls)1 1 1 1

First, subclass's Call_me method calls Super (). Call_me (), which is actually referring to the Leftsubclass.call_me () method. Then Leftsubclass.call_me () called super (). Call_me (), but then super () refers to Rightsubclass.call_me (). It is important to note that the super call is not a method of calling Leftsubclass (that is, BaseClass). It is called Rightsubclass, although it is not Leftsubclass's parent class! This is the next method, not the parent class method. Rightsubclass then calls BaseClass, and the super call guarantees that each method is executed once in the hierarchy of the class.

Reference:

1, "Python3 Object-Oriented Programming" [Plus]dusty Philips

Python multiple inheritance of diamond problems

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.