代码之家  ›  专栏  ›  技术社区  ›  cmcginty

如何混合旧式和新式python类?

  •  7
  • cmcginty  · 技术社区  · 15 年前

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

    我想知道在新的python代码库中使用旧样式类的正确方法。比如说我有两个固定的课程, . 如果我想子类 ,并转换为新样式的类( A2 地下二层 ),这就行了。但是如果我想创建一个新类 C ,从 A2 地下二层 .

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

    有关说明,请参见示例代码:

    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() 地下二层 从未初始化。


    更新-新样式类示例

    我想还不清楚在使用 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
    
    1 回复  |  直到 13 年前
        1
  •  6
  •   Lennart Regebro    15 年前

    这不是一个新旧风格混合的问题。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'
    

    这是正确的。它调用第一个类的实现。 不过,让我们用method2来尝试一下:

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

    欧普斯,错了!它应该在这里调用类c.method2(),因为即使类b不重写method2,类c也会重写method2。现在让A级成为新闻类:

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

    然后再试一次:

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

    嘿,普雷斯托,成功了。这是新样式类和旧样式类之间的方法解析顺序差异,有时将它们混合会使人感到困惑。

    注意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'
    

    如果要同时调用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'
    

    这也是每个设计。仍然没有两个基类被调用。如果你想这样做,你仍然需要显式地调用两者。