Mro
Method resolution order is used by python to parse the method call sequence. Mro is important for method calling in Multi-inheritance. There is a built-in function in Python that is closely related to Mro-Super. As the name suggests, super should look like a method to call the parent class, which is usually the same. Let's look at a piece of code:
Class A (object): <br/> def _ init _ (Self): <br/> Print 'a. _ init _ '<br/> Class B (a): <br/> def _ init _ (Self): <br/> Print' B. _ init _ '<br/> # Try to call parent's _ init _ without explicitly reference Class A <br/> super (B, self ). _ init _ () <br/> X = B () <br/> B. _ init __< br/>. _ init __< br/>
Here we use super to call the _ init __, super (B, self) of the parent class to return a bounded object (because we passed in self ).
The output shows that the call is correct. Just like calling a. _ init _ (Self) directly.
In this way, you can call the method of the base class without directly referencing the name of the base class. If we change the name of the base class, we do not need to change the call of all subclass classes.
However, super is not as simple as we thought. Super is not simply calling the so-called base class method, but calling the method of the next class in Mro, that is, the method similar to next.
# This code is excerpted from Python's super considered harmful <br/> Class A (object): <br/> def _ init _ (Self ): <br/> Print "A" <br/> super (A, self ). _ init _ () <br/> Class B (object): <br/> def _ init _ (Self ): <br/> Print "B" <br/> super (B, self ). _ init _ () <br/> class C (a): <br/> def _ init _ (self, ARG ): <br/> Print "C", "Arg =", Arg <br/> super (C, self ). _ init _ () <br/> Class D (B): <br/> def _ init _ (self, ARG ): <br/> Print "D", "Arg =", Arg <br/> super (D, self ). _ init _ () <br/> Class E (c, d): <br/> def _ init _ (self, ARG ): <br/> Print "E", "Arg =", Arg <br/> super (E, self ). _ init _ (ARG) <br/> # print "Mro:", [X. _ name _ for X in E. _ Mro _] <br/> E (10)
For this code, we may expect the output to be like this:
E Arg = 10 <br/> C Arg = 10 <br/> A <br/> D Arg = 10 <br/> B
But in fact, this code will cause errors because Python does not call the correct function as we thought.
E Arg = 10 <br/> C Arg = 10 <br/> A <br/> traceback (most recent call last): <br/> file "C: /users/Administrator/desktop/example1-2.py ", line 27, in <module> <br/> E (10) <br/> file" C: /users/Administrator/desktop/example1-2.py ", line 24, in _ init __< br/> super (E, self ). _ init _ (ARG) <br/> file "C:/users/Administrator/desktop/example1-2.py", line 14, in _ init __< br/> super (C, self ). _ init _ () <br/> file "C:/users/Administrator/desktop/example1-2.py", line 4, in _ init __< br/> super (A, self ). _ init _ () <br/> typeerror: _ init _ () Takes exactly 2 arguments (1 given)
The output of the output Mro statement commented out in the above code is given first:
Mro: ['E', 'C', 'A', 'D', 'B', 'object']
The error occurs because super (A, self). _ init _ is called when the call continues to A. _ init __. Remember that we mentioned above that super is similar to the next function and is a method that calls the next type in Mro.
The type given here is a, so the next type in Mro is D. Obviously, super will call D. _ init _ (Self ). However, D. _ init _ accepts an additional parameter Arg, so the call is incorrect.
Super does not call the method of the parent class just like its name, but calls the method of the next type in Mro.
The reference links provide suggestions for using super, which can be used as a reference.
Summary
- If the class is designed to use super, all sub-classes must call Super. Otherwise, duplicate calls may occur.
- The objective function called by super usually uses * ARGs and ** kwargs as parameters, which can solve the problem of target function parameter matching.
Mro implementation
This Mro is written by yourself according to the description in the python 2.3 method resolution order. The paper also has related implementations and is more sophisticated.
Import inspect <br/> def compute_linearization (kls): <br/> "" <br/> given a class object, calculate the Mro of the class <br/> A linerization is defined as the class plus the merge of the linerization of all bases and the list of bases <br/> "" <br /> If inspect. isclass (kls): <br/> Mro = [kls] <br/> # for each base class, we need to compute the linerization <br/> merge_list = [] <br/> for basekls in kls. _ bases __: <br/> merge_list.append (compute_linearization (basekls) <br/> # add all bases to the merge list <br/> merge_list.append ([]) <br/> for basekls in kls. _ bases __: <br/> merge_list [-1]. append (basekls) <br/> return Mro + Merge (merge_list) <br/> else: <br/> raise typeerror ("argument must a Class Object ") <br/> "" <br/> take the head of the first list, I. e l [B1] [0]; if this head is not in the tail of any of the other lists, then add it to the linearization of C and remove it from the lists in the merge, otherwise look at the head of the next list and take it, if it is a good head. then repeat the operation until all the class are removed or it is impossible to find good heads. in this case, it is impossible to construct the merge, Python 2.3 will refuse to create the class C and will raise an exception. <br/> "" <br/> def Merge (merge_list): <br/> res = [] <br/> while true: <br/> processed = false <br/> has_good_head = false <br/> For I, L in enumerate (merge_list): <br/> If Len (l ): <br/> # mark for processing <br/> processed = true <br/> head = L [0] <br/> is_good_head = true <br/> other_lists = merge_list [0: i] + merge_list [I + 1:] <br/> # Check if the head is in the tail of other lists <br/> for rest in other_lists: <br/> If head in rest [1:]: <br/> is_good_head = false <br/> Break <br/> # If is a good head, then need to remove it from other lists <br/> If is_good_head: <br/> # Save the head to the result list <br/> has_good_head = true <br/> res. append (head) <br/> for Al in merge_list: <br/> If Len (Al) and Al [0] = head: <br/> Del al [0] <br/> Break <br/> # else skip to the next list <br/> if not has_good_head: <br/> raise typeerror ("Mro error") <br/> if not processed: <br/> Break <br/> return res <br/>
Reference:
- Python's super considered harmful
- The Python 2.3 method resolution order
- Core Python Programming