你如何混合旧式和新式Python类?

cmc*_*nty 7 python class instantiation multiple-inheritance

我已经看过关于这个主题的几个问题,但我还没有找到明确的答案.

我想知道在新的Python代码库中使用旧式类的正确方法.比方说,例如,我有两个固定类,一个.如果我想要子类AB,并转换为新式类(A2B2),这是有效的.但是,如果我想从A2B2创建新的C类,则会出现问题.

因此,是否可以继续使用此方法,或者如果任何基类被定义为旧式,那么所有类都必须符合旧式吗?

请参阅示例代码以获得说明:

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()
Run Code Online (Sandbox Code Playgroud)

这段代码的输出:

class A
class A2
---
class B
class B2
---
class A
class A2
class C
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,问题是在调用中C(),B2类从未初始化.


更新 - 新样式类示例

我想还不清楚使用时正确的初始化序列应该是什么super.这是一个工作示例,其中对super的调用初始化所有基类,而不仅仅是它找到的第一个基类.

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()
Run Code Online (Sandbox Code Playgroud)

并产生输出:

class B
class B2
class A
class A2
class C
Run Code Online (Sandbox Code Playgroud)

Len*_*bro 6

这不是混合新旧类的问题.super()不调用所有基类函数,它根据方法解析顺序调用它找到的第一个函数.在这种情况下,A2反过来调用A.

如果要同时调用它们,请明确地执行此操作:

class C(A2, B2):
   def __init__(self):
      A2.__init__(self)
      B2.__init__(self)
      print 'class C'
Run Code Online (Sandbox Code Playgroud)

那应该解决它.

更新:

你所指的钻石继承问题是钻石继承情况下要调用哪个类的问题,如下所示:

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
Run Code Online (Sandbox Code Playgroud)

现在测试一下:

>>> D().method1()
'class B'
Run Code Online (Sandbox Code Playgroud)

这是对的.它调用了第一类的实现.但是,让我们尝试使用method2:

>>> D().method2()
'class A'
Run Code Online (Sandbox Code Playgroud)

Oups,错了!它应该在这里调用类C.method2(),因为即使类B不重写method2,类C也可以.现在让A类成为一个新类:

class A(object):
   def method1(self):
      print 'class A'
Run Code Online (Sandbox Code Playgroud)

然后再试一次:

>>> D().method1()
'class B'
>>> D().method2()
'class C'
Run Code Online (Sandbox Code Playgroud)

嘿presto,它的工作原理.这是新旧类的方法解析顺序差异,这有时会使它们混淆.

注意B和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 C'
Run Code Online (Sandbox Code Playgroud)

如果你想同时调用B和C,你必须明确地调用它们.

现在,如果你破坏钻石,就像在你的例子中有单独的基类一样,结果是不同的:

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'
Run Code Online (Sandbox Code Playgroud)

这也是每个设计.仍然无法调用两个基类.如果你想要这样做,你仍然必须明确地调用它们.

  • 不,答案是详尽无遗的.它根本不复杂.并且super()不会调用所有父类的所有方法,甚至不会调用合作链.声称这是令人困惑,复杂和基本方面的错误. (3认同)