Python PR

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

っていう感じですね!

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