Syntax execution of __init__ with multiple inheritance in Python

I am trying to get the correct __init__ order. The hierarchy consists of two branches. The left branch implements some abstract methods of the right branch. There is also a split in the right branch. Now I would like them to be executed: first, from top to bottom, and then from top right to left.

Is there a way to achieve this in Python 3?

So basically the following should print the numbers in order (which is not the case):

 from abc import abstractmethod, ABCMeta class L1: def __init__(self): super().__init__() print(1) class R1(metaclass=ABCMeta): def __init__(self): super().__init__() print(3) @abstractmethod def m(self): pass class L2(L1): def __init__(self): super().__init__() print(2) def m(self): pass class R2a(R1): def __init__(self): super().__init__() print(4) class R2b(R1): def __init__(self): super().__init__() print(4) class X(L2, R2a): pass class Y(L2, R2b): pass x = X() print("--") y = Y() 

Unfortunately, I cannot change the order of L2 and R2, since L2 implements the abstract methods of R2 (there will be errors if I change this).

Is it possible?

(Do you know that a good way to think about MRO to solve such a problem is easy?)

EDIT: I thought it didn't matter, but I want to note that in my real structure on the L side there is apparently a diamond like L2a (L1), L2b (L1) and L2 (L1a, L2a) completely separate some functions.

+4
source share
2 answers

What about:

 from abc import abstractmethod, ABCMeta class L1: def __init__(self): self.init() super().__init__() def init(self): print(1) class R1(metaclass=ABCMeta): def __init__(self): print(3) super().__init__() @abstractmethod def m(self): pass class L2(L1): def __init__(self): super().__init__() def init(self): super().init() print(2) def m(self): pass class R2a(R1): def __init__(self): super().__init__() print(4) class R2b(R1): def __init__(self): super().__init__() print(4) class X(L2, R2a): pass class Y(L2, R2b): pass x = X() print([cls.__name__ for cls in X.mro()]) 

what gives

 1 2 3 4 ['X', 'L2', 'L1', 'R2a', 'R1', 'object'] 

I do not think you can change the MRO, ['X', 'L2', 'L1', 'R2a', 'R1', 'object'] . But you can choose to place initialization instructions before or after super().__init__() .

Placing print statements before super().__init__() gives you print instructions in MRO order. Placing them subsequently cancels the order.

You want the order to be partially canceled: L1 to L2, R1 to R2a.

When we reach L1 by calling self.init() , we will start first at the beginning of the MRO chain and call init in the desired order: L1, L2 .

+3
source

I prefer to avoid using super:

 class A: def __init__(self): print('init A') class B: def __init__(self): print('init B') class C(B,A): def __init__(self): A.__init__(self) B.__init__(self) print('init C') c = C() 

Fingerprints:

 init A init B init C 

So, for your specific situation, just call _init_in in any order. Indeed. just try it. Diamond or diamond will fail.

EG:

 class X(L2,R2a): def __init__(self): L1.__init__(self) L2.__init__(self) R1.__init__(self) R2a.__init__(self) 

If you need to call init for things higher in the hierarchy, and you are afraid to repeatedly name certain functions of the init class for certain objects, then just create some logical flags,

For instance:

 class L1: def __init__(self): try: if self.l1_initialised: return except NameError: self.l1_initialised = True blah blah blah 
+1
source

Source: https://habr.com/ru/post/1445038/


All Articles