Pythonの参照制限(アンダースコア)がモジュールでは効かなかった話

思ってたのと違ったのでメモ。

Pythonは_(アンダースコア)から始まるオブジェクトは外部から参照しないようにする習慣があります。

また、__(アンダースコア2つ)から始まるオブジェクトは外部からの参照ができません。

実際、これを破ろうとすると実行時にエラーが出ます。例えば、次のようなプログラムを実行する時。

class TestClass:
    __private_value = "Secret!!!"

    def _pre_private_method(self):
        print(self.__private_value)

    def __private_method(self):
        print(self.__private_value)


def test_scope():
    test = TestClass()
    test._pre_private_method()
    test.__private_method()


if __name__ == "__main__":
    test_scope()

最初の_pre_private_methodは成功しますが、2つ目の__private_methodの呼び出しはちゃんと失敗してくれます。

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

やろうと思えばスコープの設定がきちんと行えるのは素晴らしいですね。

しかし、モジュール内で宣言された関数ではこの規則は効いてくれませんでした。

test_module.py

def _pre_private_method():
    print("Pre private!!!")


def __private_method():
    print("Absolutely private!!!")

test_caller.py

import test_module


if __name__ == "__main__":
    testmodule._pre_private_method()
    testmodule.__private_method()

test_callerを実行すると、

Pre private!!!
Absolutely private!!!

このように、プライベート宣言した関数にアクセスできてしまいます。

一応ディレクトリを分けてテストしてみましたが、こちらも同様にアクセスできてしまいました。

それと、書いていて気づきましたが、アンダースコア1つの場合はPEP8から「Access to a protected member」という警告が出るのですが、2つの方は警告すら出ませんね・・・

しっかりとスコープの設定をしたいならクラスを定義してちゃんとしたオブジェクト指向をしろという事でしょうか。確かにそんな気もする。

以上、ちょっとした備忘録でした。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です