シングルおよびダブルのアンダースコアに関しては、どちらも「プライベート」の同じ概念を示しています。つまり、属性(メソッドまたは「通常の」データ属性など)がオブジェクトのパブリックAPIの一部ではないことがわかります。人々はそれに直接触れることは災害を招くことであることを知っているでしょう。
さらに、ダブルリーディングアンダースコア属性(シングルリーディングアンダースコア属性ではない)は、サブクラスまたは現在のクラス外の他の場所から誤ってアクセスする可能性を低くするために名前が変更されています。あなたはまだそれらにアクセスすることができますが、ささいなことではありません。例えば:
>>> class ClassA:
... def __init__(self):
... self._single = "Single"
... self.__double = "Double"
... def getSingle(self):
... return self._single
... def getDouble(self):
... return self.__double
...
>>> class ClassB(ClassA):
... def getSingle_B(self):
... return self._single
... def getDouble_B(self):
... return self.__double
...
>>> a = ClassA()
>>> b = ClassB()
これで、以下によって作成された属性に簡単にアクセスa._single
しb._single
て取得できます。_single
ClassA
>>> a._single, b._single
('Single', 'Single')
>>> a.getSingle(), b.getSingle(), b.getSingle_B()
('Single', 'Single', 'Single')
ただし、またはインスタンスの__double
属性に直接アクセスしようとしても機能しません。a
b
>>> a.__double
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: ClassA instance has no attribute '__double'
>>> b.__double
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: ClassB instance has no attribute '__double'
そして、で定義されたメソッドClassA
はそれを直接取得できますが(いずれかのインスタンスで呼び出された場合):
>>> a.getDouble(), b.getDouble()
('Double', 'Double')
で定義されたメソッドはClassB
できません:
>>> b.getDouble_B()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in getDouble_B
AttributeError: ClassB instance has no attribute '_ClassB__double'
そして、そのエラーの中で、何が起こっているのかについてのヒントが得られます。属性名は、クラス内でアクセスされると、アクセスされ__double
ているクラスの名前を含むように名前が変更されます。にアクセスしようとすると、実際には、コンパイル時に、のアクセスに変わります。同様に。のアクセスにもなります。(のメソッドがに割り当てられ、簡潔にするためにコードに含まれていない場合、そのメソッドはに触れずに新しい属性を作成します。)この属性の他の保護はないため、次の場合でも直接アクセスできます。正しい名前を知っている:ClassA
self.__double
self._ClassA__double
ClassB
ClassB
__double
ClassA
__double
>>> a._ClassA__double, b._ClassA__double
('Double', 'Double')
では、なぜこれが問題なのですか?
この属性を処理するコードの動作を継承して変更したい場合は、いつでも問題になります。この二重アンダースコア属性に直接触れるすべてを再実装するか、クラス名を推測して名前を手動でマングルする必要があります。この二重アンダースコア属性が実際にメソッドである場合、問題はさらに悪化します。メソッドをオーバーライドするか、サブクラスでメソッドを呼び出すと、名前を手動で操作するか、メソッドを呼び出すすべてのコードを再実装して、二重アンダースコア名を使用しないようにします。 。属性に動的にアクセスすることは言うまでもなく、getattr()
:を使用して手動でマングルする必要もあります。
一方、属性は簡単に書き直されるだけなので、表面的な「保護」しか提供しません。コードは手動でマングリングすることで属性を取得できますが、コードはクラスの名前に依存し、コードをリファクタリングしたり、クラスの名前を変更したりするための努力が必要になります(同じユーザーが表示されたままになります)。名前、Pythonの一般的な方法)は、不必要にコードを壊してしまいます。また、Pythonをだまして、クラスに自分のクラスと同じ名前を付けることで、名前をマングリングすることもできます。マングルされた属性名にモジュール名が含まれていないことに注意してください。そして最後に、二重アンダースコア属性は、すべての属性リストと、表示されないすべての形式のイントロスペクションに引き続き表示されます。シングル)アンダースコア。
したがって、二重アンダースコアの名前を使用する場合は、非常に不便になる可能性があるため、非常に控えめに使用してください。また、サブクラスが再実装、オーバーライド、または直接アクセスする可能性のあるメソッドやその他の名前には使用しないでください。また、二重のアンダースコアの名前マングリングは実際の保護を提供しないことを理解してください。結局、単一の先頭のアンダースコアを使用すると、同じように勝ち、(潜在的な、将来の)苦痛が少なくなります。単一の先頭の下線を使用します。