MRO is method resolution order, which is used primarily to determine the path of a property (from which class) when multiple inheritance occurs.
In the python2.2 version, the basic idea of the algorithm is to compile a list based on the inheritance structure of each ancestor class, including the search class, and delete the duplicates by policy. However, the maintenance monotonicity has failed (sequential saving), so from the 2.3 version, a new algorithm C3 is adopted.
Why use the C3 algorithm
The C3 algorithm was first proposed to be used in Lisp, and it was applied in Python to solve the problem that the original depth-first search algorithm did not satisfy the local priority and monotonicity.
Local precedence: Refers to the order of the parent class at the time of declaration, such as C (A, A, b), and if you access the Class C object properties, you should first find class A in order of declaration, and then look for class A.
Monotonicity: If in the parse order of C, a is in front of B, then in all subclasses of C, this order must also be fulfilled.
C3 algorithm
The MRO is judged by determining a linear sequence, and then finding the path is determined by the order of the classes in the sequence. So the C3 algorithm is to generate a linear sequence.
If you inherit to a base class:
Copy the Code code as follows:
Class B (A)
At this point the MRO sequence for B is [b,a]
If you inherit to more than one base class
Copy the Code code as follows:
Class B (A1,a2,a3 ...)
This is the MRO sequence MRO (b) = [B] + merge (MRO (A1), MRO (A2), MRO (A3) ..., [A1,A2,A3])
The merge operation is the core of the C3 algorithm.
Iterates through the sequence that performs the merge operation, if the first element of a sequence is the first element in another sequence, or does not appear in another sequence, removes the element from all the execution of the merge operation sequence and merges into the current MRO.
After the merge operation, continue with the merge operation until the sequence of the merge operation is empty.
If the sequence of the merge operation cannot be empty, the description is illegal.
Example:
Copy the Code code as follows:
Class A (O):p
Class B (O):p
Class C (O):p
Class E (A, b):p
Class F (B,c):p
Class G (e,f):p
A, B, C are inherited to a base class, so the MRO sequence is [A,o], [B,o], [C,o]
Copy the Code code as follows:
MRO (e) = [E] + merge (MRO (A), MRO (B), [A/b])
= [E] + merge ([A,o], [B,o], [b])
The sequence to perform the merge operation is [A,o], [B,o], [A, b]
A is the first element in the sequence [A,o], does not appear in the sequence [B,o], and is the first element in the sequence [a, b], so a is removed from the sequence of the merge operation ([A,o], [B,o], [b]), and merged into the current Mro,[e].
MRO (E) = [E,a] + merge ([O], [B,o], [B])
The merge operation is then performed, and O is the first element in the sequence [o], but o appears in the sequence [B,o] and is not the first of these elements. Continue viewing the first element of [B,o] b,b satisfies the condition, so remove B from the sequence in which the merge operation was performed and merge into [E, A].
Copy the Code code as follows:
MRO (E) = [E,a,b] + merge ([o], [o])
= [E,a,b,o]
Code to implement the C3 algorithm
Copy the Code code as follows:
#-*-ENCODING:GBK-*-#
def mro_c3 (*CLS):
If Len (CLS) ==1:
If not cls[0].__bases__:
Return CLS
Else
Return cls+ mro_c3 (*cls[0].__bases__)
Else
SEQS = [List (MRO_C3 (c)) for C in CLS] +[list (CLS)]
res = []
While True:
Non_empty = List (filter (None, seqs))
If not non_empty:
Return tuple (RES)
For seq in Non_empty:
candidate = Seq[0]
Not_head = [s for s in Non_empty if candidate in S[1:]]
If Not_head:
candidate = None
Else
Break
If not candidate:
Raise TypeError ("Inconsistent hierarchy, no C3 MRO is possible")
Res.append (Candidate)
For seq in Non_empty:
If seq[0] = = Candidate:
Del Seq[0]