ホームページ  >  に質問  >  本文

关于python的继承的一个疑问

如图所示,B 类继承了 A 类;

当实例化对象时,B 类中没有构造函数, 应该调用父类的构造函数 __init__

但是里边的 self.__pirv() 为啥调用到父类 A__priv, 而 self.pub() 又调到 B 中的 pub

求解?

迷茫迷茫2741日前862

全員に返信(3)返信します

  • ringa_lee

    ringa_lee2017-04-18 10:30:50

    Python では、__ で始まるメソッド名はプライベートではありません。__ は Python に名前マングリングを行わせることを意味します。名前マングリングの結果は _A__priv です。この方法を使用して上書きしないでください。サブクラスでメソッドを上書きしたい場合は、__ ではなく _ のみを使用できます

    返事
    0
  • 大家讲道理

    大家讲道理2017-04-18 10:30:50

    この質問についてしばらく考えた後、私の理解は次のとおりです:

    リーリー サブクラスのインスタンスに対して

    を呼び出すと、この結果が得られます。これは私の個人的な理解ですので、間違っていたらご指摘ください、ありがとうございます。 __init__()方法时,从子类B本身中查找pub()方法,显然是存在的,因此会调用B类自身的pub()方法;然而在调用__priv()方法时,由于Python对私有成员进行了名称改编,你实际调用的是_A__priv()方法,而B类中并没有这个方法,有的只有_B__priv(),因此调用父类A中的_A__priv()

    返事
    0
  • 巴扎黑

    巴扎黑2017-04-18 10:30:50

    問題自体については、@Xavier と @Christoph がすでに詳しく説明しています


    それでも理解できない場合は、次のことを試してみてください:

    元のコード:

    リーリー

    名前のマングリングを手動で実行します:

    リーリー

    B は、以下を含む A のすべての属性を継承します。

    • B 在這裡繼承了 A 的所有屬性包含:

      • __init__

      • _A__priv

      • public

      B 自己定義了:

      • _B__priv

      • public (此處覆寫了 Apublic)

      所以最後你會看到 dir(b) 裡面有:

      • __init__ (從 A 繼承的)

      • _A__priv (從 A 繼承的)

      • _B__priv (自己定義的)

      • public (自己定義的)

      最後當 __init__ 被呼叫時, 會調用 _A__priv, 而 B 裡面的確有這個方法


      囉唆補充一下, Python 本身並沒有真正的 private 機制, 因為了解 name mangling 的人就能對以雙底線開頭的屬性做存取, 比如說我可以很輕易地寫出:

      class A:
          def __init__(self):
              self.__priv() # 等等改成 self._A__priv()
              self.public()
          def __priv(self): # 等等改成 def _A__priv(self):
              print('private of A')
          def public(self):
              print('public of A')
              
      class B(A):
          def __priv(self): # 等等改成 self._B__priv(self):
              print('private of B')
          def public(self):
              print('public of B')
              
      b = B()

      簡單來說這個機制是個:

      • 防呆 的機制, 不是個 防小人 的機制,

      • 防止意外 存取的機制, 不是個防止 刻意存取 的機制

      但是這個機制並非所有人都覺得好(個人就不喜歡, 使用雙底線開頭命名既麻煩也沒太多實際的幫助), 所以你可以在很多的 python 代碼中發現: 大家比較常使用以 單個底線 開頭的保護方式, 這種做法是個公認的慣例(註1), 對於稍有經驗的程序員來說足以防呆, 且不會有任何額外的效果和意外的狀況發生

      Ian Bicking 有一段話是這樣說的 (Ian Bicking 是 Python 大神, 這段話我是在 Luciano Ramalho 的的 Fluent Python 中看到的):

      永遠不要在前面使用兩個底線. 這是很讓人生氣的自私行為, 如果你不希望造成名稱衝突(註2), 可以明確地重整名稱(例如: _MyThing_blahblah). 實質上這與使用雙底線是同一件事情, 不過他是公開的, 雙底線是私下的行為.

      所以我的建議是, 使用 _priv 會是更好的選擇.


      註1: 以單底線開頭的屬性不會具有任何特殊的性質, 他僅僅是依靠 Python 程序員的共識而產生的具有象徵意義的符號性手法, 就好像有些語言會使用 const__init__

    • _A__priv

    • パブリック

    🎜 そして B が自分で定義しました:🎜
    • 🎜_B__priv🎜
    • 🎜public (ここでは Apublic をオーバーライドします)🎜
    🎜最後に、次の内容を含む dir(b) が表示されます:🎜
    • 🎜__init__ (A から継承)🎜
    • 🎜_A__priv (A から継承)🎜
    • 🎜_B__priv (自己定義)🎜
    • 🎜public (自己定義)🎜
    🎜最後に、__init__ が呼び出されると、_A__priv が呼び出され、B にはこのメソッドが含まれます🎜 🎜 🎜 Python 自体には実際のプライベート メカニズムがないことを付け加えておきます。名前のマングリングを理解している人は、二重アンダースコアで始まる属性にアクセスできるためです。たとえば、次のように簡単に記述できます。 リーリー 🎜簡単に言うと、このメカニズムは次のとおりです:🎜
    • 🎜🎜反愚か者🎜のメカニズムは、🎜反悪人🎜のメカニズムではありません🎜
    • 🎜🎜偶発的なアクセス🎜を防ぐメカニズムであり、🎜意図的なアクセス🎜🎜を防ぐメカニズムではありません
    🎜 しかし、誰もがこのメカニズムが良いと考えているわけではありません (私は個人的には好きではありません。二重アンダースコアで始まる名前を付けるのは面倒であまり役に立ちません)。そのため、多くの Python コードでこのメカニズムが見られます。 人々は単一の名前を使用することがよくあります。 🎜 から始まります 結論 🎜 冒頭の保護方法はよく知られている方法であり (注 1)、ある程度経験のあるプログラマにとっては、これで十分であり、追加の影響や予期せぬ事態は発生しません 🎜。 🎜Ian Bicking には次のような一節があります (Ian Bicking は Python のマスターであり、私はこの一節を Luciano Ramalho の Fluent Python で見ました):🎜
    🎜その前に 2 つのベース行を使用しないでください。これは迷惑なほど利己的です。名前の競合を引き起こしたくない場合は、名前を明示的に変更できます (例: _MyThing_blahblah)。ダブルボトムラインを使用するのと同じことですが、ダブルボトムラインはプライベートな動作であるのに対し、これはパブリックです。🎜
    🎜そこで私の提案は、_priv を使用する方が良い選択であるということです。🎜 🎜 🎜注 1: 単一のアンダースコアで始まる属性には特別なプロパティはありません。これは、一部の言語が const を使用するのと同じように、Python プログラマーの合意に依存する単なる記号的なアプローチです。定数にマークを付けると、予期せぬ状況を避けるために🎜定数が大文字で命名される🎜という合意に依存することもできます🎜 🎜注 2: プライベート プロパティで属性を保護する理由は、最も一般的な理由は名前の競合による誤ったアクセスであるためです🎜

    私が回答した質問: Python-QA

    返事
    0
  • キャンセル返事