5

使用法についてはたくさんの質問がありますがsuper()、どれも私の質問に答えていないようです。

サブクラスから呼び出す場合super().__init__()、スーパーコンストラクターのすべてのメソッド呼び出しは、実際にはサブクラスから取得されます。次のクラス構造を検討してください。

class A(object):
    def __init__(self):
        print("initializing A")
        self.a()
    def a(self):
        print("A.a()")

class B(A):
    def __init__(self):
        super().__init__()
        # add stuff for B
        self.bnum=3 # required by B.a()        
    def a(self):
        print("B.a(), bnum=%i"%self.bnum)

b=B()

で失敗します

initializing A
Traceback (most recent call last):
  File "classmagic.py", line 17, in 
    b=B()
  File "classmagic.py", line 11, in __init__
    super().__init__()
  File "classmagic.py", line 5, in __init__
    self.a()
  File "classmagic.py", line 15, in a
    print("B.a(), bnum=%i"%self.bnum)
AttributeError: 'B' object has no attribute 'bnum'

ここでは、スーパーコンストラクターを呼び出して、B()いくつかの基本構造を初期化します(その一部は独自の関数として実行されますa())。ただし、a()関数もオーバーライドすると、この実装は、のコンストラクターを呼び出すときに使用されます。コンストラクターは、何も知らず、異なる内部変数を使用する可能性Aがあるため失敗します。AB

これは直感的である場合とそうでない場合がありますが、すべてのメソッドAがそこに実装されている関数にのみアクセスできるようにする場合はどうすればよいですか?

4

4 に答える 4

5

コードでオーバーライドできない特定のプライベートメソッドを呼び出す必要ある場合は、2つのアンダースコアで始まる名前を使用します。

class A(object):
    def __init__(self):
        print("initializing A")
        self.__a()
    def __a(self):
        print("A.a()")

class B(A):
    def __init__(self):
        super().__init__()
        # add stuff for B
        self.bnum=3 # required by B.a()        
    def __a(self):
        print("B.__a(), bnum=%i"%self.bnum)

Pythonは、サブクラスが独自のバージョンでそれらを上書きする可能性を最小限に抑えるために、クラス名(およびアンダースコア)を追加することによって、そのようなメソッド名を「マングル」します。

PEP 8 Pythonスタイルガイドには、プライベート名のマングリングについて次のように書かれています。

クラスがサブクラス化されることを意図していて、サブクラスに使用させたくない属性がある場合は、先頭に2つのアンダースコアを付け、末尾にアンダースコアを付けないように名前を付けることを検討してください。これにより、Pythonの名前マングリングアルゴリズムが呼び出され、クラスの名前が属性名にマングルされます。これにより、サブクラスに同じ名前の属性が誤って含まれている場合に、属性名の衝突を回避できます。

注1:マングルされた名前には単純なクラス名のみが使用されるため、サブクラスが同じクラス名と属性名の両方を選択した場合でも、名前の衝突が発生する可能性があることに注意してください。

注2:名前マングリングは、デバッグなどの特定の用途に使用でき、 __getattr__()利便性が低下する可能性があります。ただし、名前マングリングアルゴリズムは十分に文書化されており、手動で簡単に実行できます。

注3:誰もが名前マングリングを好むわけではありません。偶発的な名前の衝突を回避する必要性と、高度な発信者による潜在的な使用とのバランスをとるようにしてください。

于 2012-09-18T13:42:37.880 に答える
3

を呼び出すself.a()のではなく、を使用する必要がありますA.a(self)。ただし、これは特定のクラスのすべてのメソッドで行うのは一般的ではないため、から継承する必要があるかどうかを実際に再評価するBA必要があります。

于 2012-09-18T13:45:02.857 に答える
0

この呼び出しを検討してください:

class B(A):
    def __init__(self):
        A.__init__(self)

これは、を呼び出すと何が起こるかですsuper().__init__()。これにより、が呼び出されますself.a()。これはもちろんクラスの関数aであり、クラスの関数であるためではBありません。Martijnが述べたように、二重アンダースコア名を使用することも、クラス名を明示的に使用することもできますが、それ以外の場合は、スーパークラスからオーバーライドされたメソッドを呼び出すことはできません。AselfB

于 2012-09-18T13:47:26.123 に答える
0

次のインスタンス化手順を実行すると、次のようになりますB

  • 私たちはsuper(B,self).__init__、つまり、と呼びますA.__init__
  • これはself.a()、つまり、B.a()私たちの場合、
  • を使用しますself.bnum

bnumそれがまだ定義されていないことを除いて...だから、 AttributeError

この特定のケースでは、電話をかける前にbnuminを定義するだけで十分です。B.__init__ super(B,self).__init__

class B(A):
    def __init__(self):
       self.bnum=3
       super(B, self).__init__()

名前マングリングの暗くて暗いパスに進む前に、時間をかけてサブクラスのコードを整理することをお勧めします。親のに実行する場合、いくつかの特別な変数を初期化する場合、または親のに実行する場合は、いくつかのデフォルトを置き換えます。 ?

于 2012-09-18T13:49:39.557 に答える