Pythonの変数やメソッドをプライベート属性にするために、名前をアンダースコア2個で始める人や記事をみかけますが、「PEP8: Pythonコードのスタイルガイド」ではプライベート属性はアンダースコア1個で始めることを推奨してます。
PEP8での説明
_single_leading_underscore
: "内部でだけ使う" ことを示します。 たとえばfrom M import *
は、アンダースコアで始まる名前のオブジェクトをimportしません。__double_leading_underscore
: クラスの属性に名前を付けるときに、名前のマングリング機構を呼び出します (クラスFoobar
の__boo
という名前は_FooBar__boo
になります。以下も参照してください
一般的には、アンダースコアを名前の先頭に二つ付けるやり方は、サブクラス化されるように設計されたクラスの属性が衝突したときに、それを避けるためだけに使うべきです。
マングリング機構
名前の最初をアンダースコア2個にすると、名前のマングリング機構(名前修飾)が働き、クラス固有の名前になります。
サブクラスで同じ名前を再定義しても別物として扱われ、サブクラスでの再定義(名前衝突)による影響を受けなくなります。
アンダースコア2個にしたのが原因で意図しない動作結果になることもありますのでご注意ください。
マングリング機構を利用したサンプルコードを以下に示します。
サンプルコード
以下のプログラムを実行すると、アンダースコア2個で始める名前は、サブクラスで同じ名前を定義しても別物として扱われ、処理が書いてあるクラスの属性に強制されることがわかります。
class Base:
def __init__(self):
self.value = "Base.value"
self._value = "Base._value"
self.__value = "Base.__value"
def method(self):
print("Base.method")
def _method(self):
print("Base._method")
def __method(self):
print("Base.__method")
def base(self):
print('base():')
print(self.value)
print(self._value)
print(self.__value) # サブクラスと名前衝突しても自分のを使う
self.method()
self._method()
self.__method() # サブクラスと名前衝突しても自分のを使う
class Sub(Base):
def __init__(self):
super().__init__()
self.value = "Sub.value"
self._value = "Sub._value"
self.__value = "Sub.__value"
def method(self):
print("Sub.method")
def _method(self):
print("Sub._method")
def __method(self):
print("Sub.__method")
def sub(self):
print('sub():')
print(self.value)
print(self._value)
print(self.__value) # サブクラスと名前衝突しても自分のを使う
self.method()
self._method()
self.__method() # サブクラスと名前衝突しても自分のを使う
class SubSub(Sub):
def __init__(self):
super().__init__()
self.value = "SubSub.value"
self._value = "SubSub._value"
self.__value = "SubSub.__value"
def method(self):
print("SubSub.method")
def _method(self):
print("SubSub._method")
def __method(self):
print("SubSub.__method")
def subsub(self):
print('subsub():')
print(self.value)
print(self._value)
print(self.__value) # サブクラスと名前衝突しても自分のを使う
self.method()
self._method()
self.__method() # サブクラスと名前衝突しても自分のを使う
subsub = SubSub()
subsub.base()
print()
subsub.sub()
print()
subsub.subsub()
base():
SubSub.value
SubSub._value
Base.__value
SubSub.method
SubSub._method
Base.__method
sub():
SubSub.value
SubSub._value
Sub.__value
SubSub.method
SubSub._method
Sub.__method
subsub():
SubSub.value
SubSub._value
SubSub.__value
SubSub.method
SubSub._method
SubSub.__method
他言語との比較
C++, C#, Java でいうところの protected が Pythonでは アンダースコア1個、private が アンダースコア2個 に相当します。