This article mainly introduces the new python multi-inheritance algorithm C3, which requires complex algorithms. This article describes in detail the new algorithm C3, for more information, see mro (method resolution order). It is mainly used to determine the path of an attribute (from which class) when multiple inheritance occurs ).
In python2.2, the basic idea of an algorithm is to compile a list based on the inheritance structure of each ancestor class, including the searched classes, and delete duplicates according to the policy. However, it failed to maintain monotonicity (sequential storage), so from version 2.3, the new algorithm C3 was adopted.
Why the C3 algorithm
The C3 algorithm was first proposed for Lisp and used in Python to solve the problem that the original deep-priority search algorithm does not meet the local priority and monotonicity.
Local priority: refers to the order of the parent class during declaration, such as C (A, B). If Class C object attributes are accessed, Class A should be checked first according to the declaration order, then look for Class B.
Monotonicity: if A is at the top of B in the resolution sequence of C, then it must satisfy this order in all subclasses of C.
C3 algorithm
To judge mro, you must first determine a linear sequence, and then the search path is determined by the sequence of classes in the sequence. Therefore, the C3 algorithm generates a linear sequence.
If it is inherited to a base class:
The code is as follows:
Class B ()
In this case, the mro sequence of B is [B, A].
If you inherit multiple base classes
The code is as follows:
Class B (A1, A2, A3 ...)
At this time, the mro sequence mro (B) of B = [B] + merge (mro (A1), mro (A2), mro (A3 )..., [A1, A2, A3])
Merge operations are the core of the C3 algorithm.
Traverses the sequence of merge operations. if the first element of a sequence is the first element of another sequence, or does not appear in other sequences, then, this element is deleted from all execution sequences of merge operations and merged to the current mro.
The sequence after the merge operation continues the merge operation until the sequence of the merge operation is empty.
If the merge operation sequence cannot be empty, it indicates that it is invalid.
Example:
The code is as follows:
Class A (O): pass
Class B (O): pass
Class C (O): pass
Class E (A, B): pass
Class F (B, C): pass
Class G (E, F): pass
A, B, and C all inherit to A base class, so the mro sequence is [A, O], [B, O], and [C, O] in sequence.
The code is as follows:
Mro (E) = [E] + merge (mro (A), mro (B), [A, B])
= [E] + merge ([A, O], [B, O], [A, B])
The sequence for executing merge operations is [A, O], [B, O], and [A, B].
A is the first element in the sequence [A, O]. it does not appear in sequence [B, O] and is also the first element in sequence [A, B, therefore, A is deleted from the sequence ([A, O], [B, O], and [A, B]) that executes the merge operation and merged to the current mro and [E.
Mro (E) = [E, A] + merge ([O], [B, O], [B])
Then perform the merge operation. O is the first element in the sequence [O], but O appears in the sequence [B, O] and is not the first element. Continue to check that the first element B and B of [B, O] meet the conditions. Therefore, delete B from the sequence in which the merge operation is executed and merge it into [E,.
The code is as follows:
Mro (E) = [E, A, B] + merge ([O], [O])
= [E, A, B, O]
Code for implementing the C3 algorithm
The code is 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]