Python

【Python】プライベートな属性の定義【マングリング】

この記事では、Pythonでプライベートな属性を定義する方法を解説します。

クラスにプライベートな属性を定義することで外部から参照できない属性を定義することができます。ちなみに、属性を隠蔽することを「カプセル化」と言います。

それでは、プライベートな属性を定義する方法を見ていきましょう!

プライベートな属性の実装方法

Python でプライベートな属性を定義するには、_(アンダーバー) を識別子の先頭に1つ記述して定義します。

class TestClass:
    _cv = 'クラス変数'
    def __init__(self):
        self._ic = 'インスタンス変数'
    
    def _method(self):
        return 'メソッド'

上記ではプライベートなクラス変数、インスタンス変数、メソッドを定義しました。

外部から呼び出せるか試してみましょう!

tc = TestClass()
print(tc._cv, tc._ic, tc._method())

実行結果

クラス変数 インスタンス変数 メソッド

全部普通に呼び出せるー😅
実は Python では、完全にプライベートな属性を定義できないんです!

先頭にアンダーバーを 1つ付けるのは慣習であり、言語的な強制力はありません。なので、先ほど定義した属性たちは「プライベートとして扱おう属性」です。

エディタによっては、アンダーバーを付けることでその属性が候補に表示されなくなります

マングリング

識別子の前にアンダーバーを 2つ付けることでプライベートっぽい属性を定義することができます。

class TestClass:
    __cv = 'クラス変数'
    def __init__(self):
        self.__ic = 'インスタンス変数'
    
    def __method(self):
        return 'メソッド'

外部から呼び出せるか試してみます。

tc = TestClass()
print(tc.__cv, tc.__ic, tc.__method())

実行結果

AttributeError: 'TestClass' object has no attribute '__cv'

エラーの内容を見てみると「TestClassオブジェクト には、__cv という属性は無いよ😡」とのことです。

「プライベートにできるじゃん!」っと思った方もいらっしゃるかもしれませんが、これは「マングリング」によって属性名が _クラス名__識別子 の形に置換されたのでエラーが発生しているに過ぎません。

試しに置換された形で属性を呼び出してみると...

tc = TestClass()
print(tc._TestClass__cv, tc._TestClass__ic, tc._TestClass__method())

実行結果

クラス変数 インスタンス変数 メソッド

普通に呼び出せます❗️

完全にプライベートというわけではありませんが、誤って呼び出してしまうことはありえないのでプライベートな属性として扱うことができます。

ちなみに、クラス内部からは __属性名 の形で呼び出すことができます。

class TestClass:
    def __init__(self):
        self.__ic = 'インスタンス変数'
    
    def method(self):
        print(self.__ic)


tc = TestClass()
tc.method()

実行結果

インスタンス変数

まとめ

この記事では、Python の属性をプライベートにする方法を解説しました。

  • Python では完全にプライベートな属性は実装できない
  • 慣習的に属性の前に「_(アンダーバー)」を付ける
  • マングリングを使うことで誤って呼び出すことを防げる

っていう感じですね❗️

それでは今回の内容はここまでです。ではまたどこかで〜( ・∀・)ノ