如图所示,B 类继承了 A 类;
B
A
当实例化对象时,B 类中没有构造函数, 应该调用父类的构造函数 __init__
__init__
但是里边的 self.__pirv() 为啥调用到父类 A 的 __priv, 而 self.pub() 又调到 B 中的 pub
self.__pirv()
__priv
self.pub()
pub
求解?
业精于勤,荒于嬉;行成于思,毁于随。
Python では、__ で始まるメソッド名はプライベートではありません。__ は Python に名前マングリングを行わせることを意味します。名前マングリングの結果は _A__priv です。この方法を使用して上書きしないでください。サブクラスでメソッドを上書きしたい場合は、__ ではなく _ のみを使用できます
この質問についてしばらく考えた後、私の理解は次のとおりです:
を呼び出すと、この結果が得られます。これは私の個人的な理解ですので、間違っていたらご指摘ください、ありがとうございます。 __init__()方法时,从子类B本身中查找pub()方法,显然是存在的,因此会调用B类自身的pub()方法;然而在调用__priv()方法时,由于Python对私有成员进行了名称改编,你实际调用的是_A__priv()方法,而B类中并没有这个方法,有的只有_B__priv(),因此调用父类A中的_A__priv()
__init__()
pub()
__priv()
_A__priv()
_B__priv()
問題自体については、@Xavier と @Christoph がすでに詳しく説明しています
それでも理解できない場合は、次のことを試してみてください:
元のコード:
名前のマングリングを手動で実行します:
B は、以下を含む A のすべての属性を継承します。
_A__priv
public
而 B 自己定義了:
_B__priv
public (此處覆寫了 A 的 public)
所以最後你會看到 dir(b) 裡面有:
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 會是更好的選擇.
_priv
註1: 以單底線開頭的屬性不會具有任何特殊的性質, 他僅僅是依靠 Python 程序員的共識而產生的具有象徵意義的符號性手法, 就好像有些語言會使用 const__init__
const
パブリック
🎜その前に 2 つのベース行を使用しないでください。これは迷惑なほど利己的です。名前の競合を引き起こしたくない場合は、名前を明示的に変更できます (例: _MyThing_blahblah)。ダブルボトムラインを使用するのと同じことですが、ダブルボトムラインはプライベートな動作であるのに対し、これはパブリックです。🎜
const code> を使用するのと同じように、Python プログラマーの合意に依存する単なる記号的なアプローチです。定数にマークを付けると、予期せぬ状況を避けるために🎜定数が大文字で命名される🎜という合意に依存することもできます🎜 🎜注 2: プライベート プロパティで属性を保護する理由は、最も一般的な理由は名前の競合による誤ったアクセスであるためです🎜 私が回答した質問: Python-QA
私が回答した質問: Python-QA
Python では、__ で始まるメソッド名はプライベートではありません。__ は Python に名前マングリングを行わせることを意味します。名前マングリングの結果は _A__priv です。この方法を使用して上書きしないでください。サブクラスでメソッドを上書きしたい場合は、__ ではなく _ のみを使用できます
この質問についてしばらく考えた後、私の理解は次のとおりです:
リーリー サブクラスのインスタンスに対してを呼び出すと、この結果が得られます。これは私の個人的な理解ですので、間違っていたらご指摘ください、ありがとうございます。
__init__()
方法时,从子类B
本身中查找pub()
方法,显然是存在的,因此会调用B
类自身的pub()
方法;然而在调用__priv()
方法时,由于Python对私有成员进行了名称改编,你实际调用的是_A__priv()
方法,而B
类中并没有这个方法,有的只有_B__priv()
,因此调用父类A
中的_A__priv()
問題自体については、@Xavier と @Christoph がすでに詳しく説明しています
それでも理解できない場合は、次のことを試してみてください:
元のコード:
リーリー名前のマングリングを手動で実行します:
リーリーB
は、以下を含むA
のすべての属性を継承します。B
在這裡繼承了A
的所有屬性包含:__init__
_A__priv
public
而
B
自己定義了:_B__priv
public
(此處覆寫了A
的public
)所以最後你會看到
dir(b)
裡面有:__init__
(從A
繼承的)_A__priv
(從A
繼承的)_B__priv
(自己定義的)public
(自己定義的)最後當
__init__
被呼叫時, 會調用_A__priv
, 而B
裡面的確有這個方法囉唆補充一下, Python 本身並沒有真正的 private 機制, 因為了解 name mangling 的人就能對以雙底線開頭的屬性做存取, 比如說我可以很輕易地寫出:
簡單來說這個機制是個:
防呆 的機制, 不是個 防小人 的機制,
防止意外 存取的機制, 不是個防止 刻意存取 的機制
但是這個機制並非所有人都覺得好(個人就不喜歡, 使用雙底線開頭命名既麻煩也沒太多實際的幫助), 所以你可以在很多的 python 代碼中發現: 大家比較常使用以 單個底線 開頭的保護方式, 這種做法是個公認的慣例(註1), 對於稍有經驗的程序員來說足以防呆, 且不會有任何額外的效果和意外的狀況發生
Ian Bicking 有一段話是這樣說的 (Ian Bicking 是 Python 大神, 這段話我是在 Luciano Ramalho 的的 Fluent Python 中看到的):
所以我的建議是, 使用
_priv
會是更好的選擇.註1: 以單底線開頭的屬性不會具有任何特殊的性質, 他僅僅是依靠 Python 程序員的共識而產生的具有象徵意義的符號性手法, 就好像有些語言會使用
const
__init__
_A__priv
パブリック
B
が自分で定義しました:🎜_B__priv
🎜public
(ここではA
のpublic
をオーバーライドします)🎜dir(b)
が表示されます:🎜__init__
(A
から継承)🎜_A__priv
(A
から継承)🎜_B__priv
(自己定義)🎜public
(自己定義)🎜__init__
が呼び出されると、_A__priv
が呼び出され、B
にはこのメソッドが含まれます🎜 🎜 🎜 Python 自体には実際のプライベート メカニズムがないことを付け加えておきます。名前のマングリングを理解している人は、二重アンダースコアで始まる属性にアクセスできるためです。たとえば、次のように簡単に記述できます。 リーリー 🎜簡単に言うと、このメカニズムは次のとおりです:🎜_priv
を使用する方が良い選択であるということです。🎜 🎜 🎜注 1: 単一のアンダースコアで始まる属性には特別なプロパティはありません。これは、一部の言語がconst code> を使用するのと同じように、Python プログラマーの合意に依存する単なる記号的なアプローチです。定数にマークを付けると、予期せぬ状況を避けるために🎜定数が大文字で命名される🎜という合意に依存することもできます🎜 🎜注 2: プライベート プロパティで属性を保護する理由は、最も一般的な理由は名前の競合による誤ったアクセスであるためです🎜
私が回答した質問: Python-QA