How do you mix old-style and new-style Python classes?
关于这个话题,我看到了一些问题,但我还没有找到一个明确的答案。
我想知道在新的Python代码库中使用旧样式类的正确方法。例如,我有两个固定类,A和B。如果我想子类A和B,并转换为新样式的类(A2和B2),这是可行的。但是,如果我想创建一个新的C类,从A2和B2有一个问题。
因此,是否可以继续使用此方法,或者如果将任何基类定义为旧样式,所有类都必须符合旧样式?
请参见示例代码进行说明:
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 | class A: def __init__(self): print 'class A' class B: def __init__(self): print 'class B' class A2(A,object): def __init__(self): super(A2, self).__init__() print 'class A2' class B2(B,object): def __init__(self): super(B2, self).__init__() print 'class B2' class C(A2, B2): def __init__(self): super(C,self).__init__() print 'class C' A2() print '---' B2() print '---' C() |
此代码的输出:
1 2 3 4 5 6 7 8 9 | class A class A2 --- class B class B2 --- class A class A2 class C |
如您所见,问题是在对
更新-新样式类示例
我想在使用
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 | class A(object): def __init__(self): super(A, self).__init__() print 'class A' class B(object): def __init__(self): super(B, self).__init__() print 'class B' class A2(A): def __init__(self): super(A2, self).__init__() print 'class A2' class B2(B): def __init__(self): super(B2, self).__init__() print 'class B2' class C(A2, B2): def __init__(self): super(C, self).__init__() print 'class C' C() |
并产生输出:
1 2 3 4 5 | class B class B2 class A class A2 class C |
这不是混合新旧样式类的问题。super()不调用所有的基类函数,它调用根据方法解析顺序找到的第一个函数。在这种情况下,A2又称A。
如果要同时调用这两者,请显式执行以下操作:
1 2 3 4 5 | class C(A2, B2): def __init__(self): A2.__init__(self) B2.__init__(self) print 'class C' |
这应该能解决问题。
更新:
正如您所提到的菱形继承问题,是在菱形继承情况下调用哪个类的问题,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | class A: def method1(self): print 'class A' def method2(self): print 'class A' class B(A): def method1(self): print 'class B' class C(A): def method1(self): print 'class C' def method2(self): print 'class C' class D(B, C): pass |
现在测试一下:
1 2 | >>> D().method1() 'class B' |
这是正确的。它调用第一类的实现。不过,让我们用方法2来尝试一下:
1 2 | >>> D().method2() 'class A' |
哎呀,错了!它应该在这里调用类C.method2(),因为即使类B不重写method2,类C也会这样做。现在把A班变成一个新的风格班:
1 2 3 | class A(object): def method1(self): print 'class A' |
再试一次:
1 2 3 4 | >>> D().method1() 'class B' >>> D().method2() 'class C' |
嘿,普雷斯托,它起作用了。这是新样式类和旧样式类之间的方法解析顺序差异,这有时会使混合它们变得混乱。
注意B和C在任何时候都不会被调用。这是真的,即使我们称之为超级。
1 2 3 4 5 6 7 8 9 10 11 | class D(B, C): def method1(self): super(D, self).method1() def method2(self): super(D, self).method2() >>> D().method1() 'class B' >>> D().method2() 'class C' |
如果您想同时调用B和C,则必须显式调用这两者。
现在,如果您像在示例中有单独的基类一样不破坏菱形,则结果是不同的:
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 | class A1(object): def method1(self): print 'class A1' def method2(self): print 'class A1' class A2(object): def method1(self): print 'class A2' def method2(self): print 'class A2' class B(A1): def method1(self): print 'class B' class C(A2): def method1(self): print 'class C' def method2(self): print 'class C' class D(B, C): def method1(self): super(D, self).method1() def method2(self): super(D, self).method2() >>> D().method1() 'class B' >>> D().method2() 'class A1' |
这也是按设计的。仍然没有调用两个基类。如果您希望发生这种情况,您仍然必须明确地调用这两者。