8

このトピックに関するいくつかの質問を見てきましたが、決定的な答えを見つけることができませんでした。

新しい Python コード ベースで古いスタイルのクラスを使用する適切な方法を知りたいです。たとえば、ABという 2 つの固定クラスがあるとします。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これは、スーパーへの呼び出しが最初に見つかったものだけでなく、すべての基本クラスを初期化する実際の例です。

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'

正解です。最初のクラスの実装を呼び出します。ただし、me​​thod2 でこれを試してみましょう。

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

おっと、間違っています!クラス B は method2 をオーバーライドしませんが、クラス C はオーバーライドするため、ここでクラス C.method2() を呼び出す必要があります。クラス A を新しいスタイルのクラスにします。

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

そしてさらに試みる:

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

そしてちょっとプレスト、それは動作します。これは、新しいスタイルのクラスと古いスタイルのクラスのメソッド解決順序の違いであり、混合すると混乱を招くことがあります。

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'

これもデザイン次第。2 つの基本クラスが呼び出される場所はまだありません。それを実現したい場合は、両方を明示的に呼び出す必要があります。

于 2009-09-15T08:55:16.483 に答える