Pythonのアンダースコア2個で始まる名前は非公開だけでなくマングリング機構を利用してサブクラスに継承しないために使う

Pythonの変数やメソッドをプライベート属性にするために、名前を**アンダースコア2個**で始める人や記事をみかけますが、「[PEP8: Pythonコードのスタイルガイド](https://pep8-ja.readthedocs.io/ja/latest/)」ではプライベート属性は**アンダースコア1個**で始めることを推奨してます。

## PEP8での説明

https://pep8-ja.readthedocs.io/ja/latest/
> - `_single_leading_underscore`: **"内部でだけ使う"** ことを示します。 たとえば `from M import *` は、アンダースコアで始まる名前のオブジェクトをimportしません。
> - `__double_leading_underscore`: クラスの属性に名前を付けるときに、**名前のマングリング機構**を呼び出します (クラス `Foobar` の `__boo` という名前は `_FooBar__boo` になります。以下も参照してください
> 
> --- 
> 
> 一般的には、**アンダースコアを名前の先頭に二つ付けるやり方は、サブクラス化されるように設計されたクラスの属性が衝突したときに、それを避けるためだけに使うべきです**。

## マングリング機構

名前の最初を**アンダースコア2個**にすると、名前のマングリング機構（[名前修飾](https://ja.wikipedia.org/wiki/%E5%90%8D%E5%89%8D%E4%BF%AE%E9%A3%BE)）が働き、クラス固有の名前になります。
サブクラスで同じ名前を再定義しても別物として扱われ、サブクラスでの再定義（名前衝突）による影響を受けなくなります。
アンダースコア2個にしたのが原因で**意図しない動作結果になることもあります**のでご注意ください。
マングリング機構を利用したサンプルコードを以下に示します。

## サンプルコード

以下のプログラムを実行すると、アンダースコア2個で始める名前は、サブクラスで同じ名前を定義しても別物として扱われ、処理が書いてあるクラスの属性に強制されることがわかります。

```py
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()
```

```text:実行結果
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個 に相当します。