8

我已经看到了一些关于这个主题的问题,但我还没有找到明确的答案。

我想知道在新的 Python 代码库中使用旧式类的正确方法。例如,假设我有两个固定类AB。如果我想继承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()

此代码的输出:

class A
class A2
---
class B
class B2
---
class A
class A2
class C

如您所见,问题是在调用 时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()

并产生输出:

class B
class B2
class A
class A2
class C
4

1 回答 1

7

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

如果您想同时调用两者,请明确执行:

class C(A2, B2):
   def __init__(self):
      A2.__init__(self)
      B2.__init__(self)
      print 'class C'

那应该解决它。

更新:

您所指的菱形继承问题是在菱形继承情况下调用哪个类的问题,如下所示:

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

现在测试一下:

>>> D().method1()
'class B'

这是对的。它调用第一类的实现。但是,让我们用方法 2 试试这个:

>>> D().method2()
'class A'

哎呀,错了!它应该在这里调用类 C.method2(),因为即使类 B 没有覆盖 method2,类 C 也会。现在让 A 类成为一个新样式的类:

class A(object):
   def method1(self):
      print 'class A'

然后再试一次:

>>> D().method1()
'class B'
>>> D().method2()
'class C'

嘿presto,它的工作原理。这是新式和旧式类之间的方法解析顺序差异,这也是有时混淆它们的原因。

注意 B 和 C 是如何被调用的。即使我们调用 super 也是如此。

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,你必须显式调用两者。

现在,如果您拆开钻石,就像在您的示例中具有单独的基类一样,结果会有所不同:

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'

这也是每个设计。仍然没有调用两个基类。如果您希望这种情况发生,您仍然必须明确调用两者。

于 2009-09-15T08:55:16.483 回答