在Python中使用多重继承强制执行__init__执行

Force specific __init__ execution with multiple inheritance in Python

我正在努力争取执行__init__死刑的权利。层次结构由两个分支组成。左分支实现了右分支的一些抽象方法。在右边的树枝上也有一个裂口。现在我想让他们执行:先左上到下,然后右上到下。

在Python3中有实现这一点的方法吗?

所以基本上,下面应该按顺序打印数字(它没有):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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()

不幸的是,我无法更改l2和r2的顺序,因为l2实现了r2的抽象方法(如果我更改该方法,将出现错误)。

有可能吗?

(你知道一个很好的方法来考虑MRO来轻松解决这类问题吗?)

编辑:我认为我不重要,但我想指出的是,在我真正的结构中,在L面实际上有一个钻石,像L2A(L1),L2B(L1)和L2(L1A,L2A)。这是为了完全分离一些功能。


怎么样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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()])

会产生

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

我认为你不能更改MRO,['X', 'L2', 'L1', 'R2a', 'R1', 'object']。但是您可以选择将初始化语句放在super().__init__()之前或之后。

把打印对账单放在super().__init__()之前,可以按照MRO的顺序给您打印对账单。之后再放,顺序颠倒。

您希望部分颠倒顺序:l1在l2之前,r1在r2a之前。

当我们到达l1时,通过调用self.init(),我们可以从MRO链的开始重新开始,并按所需的顺序调用initL1, L2


我更喜欢避免使用super:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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()

打印内容:

1
2
3
init A
init B
init C

因此,对于您的具体情况,只需按您想要的顺序调用_init_即可。真正地。试试看。不管是钻石还是没有钻石,都会很好的。

如:

1
2
3
4
5
6
class X(L2,R2a):
    def __init__(self):
        L1.__init__(self)
        L2.__init__(self)
        R1.__init__(self)
        R2a.__init__(self)

如果需要为层次结构中更高层的内容调用init,并且害怕为某些对象重复调用某些类的init函数,那么只需制作一些布尔标记。

例如:

1
2
3
4
5
6
7
8
class L1:
    def __init__(self):
        try:
            if self.l1_initialised:
                return
        except NameError:
            self.l1_initialised = True
        blah blah blah