Python のお勉強9 ( プライベートメンバの定義 )

Python のお勉強シリーズ」第9回目は、プライベートメンバの定義についてサンプルコード書いてみました。

■ privateMember.py

#coding: cp932

class Test:
    def __init__(self):
        self.__member = "private member" #private なメンバに値を代入

    #private なメソッドを定義
    def __privateMethod(self):
        print(self.__member)

    def method(self):
        self.__privateMethod()

if __name__ == "__main__":
    instance = Test()

    print("----- call method() -----")
    instance.method()

    print("----- access private member -----")
    #private なメンバにはアクセスできず "AttributeError: 'Test' object has no attribute '__member'" となる (*1)
    instance.__member

    print("----- call private method -----")
    #private なメソッドは実行できず "AttributeError: 'Test' object has no attribute '__method'" となる (*2)
    instance.__method()

■ 実行結果

----- call method() -----
private member
----- access private member -----
Traceback (most recent call last):
  File "privateMember.py", line 22, in <module>
    instance.__member
AttributeError: 'Test' object has no attribute '__member'

※ (*1) でエラーになるので (*2) まで行き着きませんが・・・

Python には言語としてプライベートなメンバってものは厳密にはないみたいですが、2つ以上の下線 "_" で始まる、かつ、末尾の下線が1つ以下の属性 / メソッドについては内部的に識別子が _<クラス名>__<メンバ名> という形に変換されるとのこと。これにより定義した通りの名前では属性アクセス、メソッド呼び出しができないことになります ( _<クラス名>__<メンバ名> とすれば普通にアクセス、呼び出し可能ですが )。

・9. クラス — Python 3.4.3 ドキュメント
- 9.6. プライベート変数
http://docs.python.jp/3.4/tutorial/classes.html#tut-private


上記の通り、_<クラス名>__<メンバ名> に変換されているだけなので、今回のサンプルコードだと _Test__member、_Test__privateMethod とすると普通に属性アクセス、メソッド呼び出しが可能です。

■ privateMember2.py

#coding: cp932

import inspect

class Test:
    def __init__(self):
        self.__member = "private member" #private なメンバに値を代入

    #private なメソッドを定義
    def __privateMethod(self):
        print(self.__member)

    def method(self):
        self.__privateMethod()

if __name__ == "__main__":
    instance = Test()

    print("----- call method() -----")
    instance.method()

    print("----- access private member -----")
    print(instance._Test__member)

    print("----- call private method -----")
    instance._Test__privateMethod()

    print("----- get instance member -----")
    print(inspect.getmembers(instance)) #インスタンスの全メンバを取得する _Test__member, _Test__privateMethod が存在することが確認できる

■ 実行結果

----- call method() -----
private member
----- access private member -----
private member
----- call private method -----
private member
----- get instance member -----
[('_Test__member', 'private member'), ('_Test__privateMethod', <bound method Test.__privateMe
 <__main__.Test object at 0x01E55750>>), ('__class__', <class '__main__.Test'>), ('__delattr_
thod-wrapper '__delattr__' of Test object at 0x01E55750>), ('__dict__', {'_Test__member': 'pr
ember'}), ('__dir__', <built-in method __dir__ of Test object at 0x01E55750>), ('__doc__', No
__eq__', <method-wrapper '__eq__' of Test object at 0x01E55750>), ('__format__', <built-in me
format__ of Test object at 0x01E55750>), ('__ge__', <method-wrapper '__ge__' of Test object a
55750>), ('__getattribute__', <method-wrapper '__getattribute__' of Test object at 0x01E55750
_gt__', <method-wrapper '__gt__' of Test object at 0x01E55750>), ('__hash__', <method-wrapper
h__' of Test object at 0x01E55750>), ('__init__', <bound method Test.__init__ of <__main__.Te
ct at 0x01E55750>>), ('__le__', <method-wrapper '__le__' of Test object at 0x01E55750>), ('__
<method-wrapper '__lt__' of Test object at 0x01E55750>), ('__module__', '__main__'), ('__ne__
hod-wrapper '__ne__' of Test object at 0x01E55750>), ('__new__', <built-in method __new__ of
ject at 0x5D9B61A0>), ('__reduce__', <built-in method __reduce__ of Test object at 0x01E55750
_reduce_ex__', <built-in method __reduce_ex__ of Test object at 0x01E55750>), ('__repr__', <m
rapper '__repr__' of Test object at 0x01E55750>), ('__setattr__', <method-wrapper '__setattr_
est object at 0x01E55750>), ('__sizeof__', <built-in method __sizeof__ of Test object at 0x01
), ('__str__', <method-wrapper '__str__' of Test object at 0x01E55750>), ('__subclasshook__',
-in method __subclasshook__ of type object at 0x02536030>), ('__weakref__', None), ('method',
 method Test.method of <__main__.Test object at 0x01E55750>>)]


inspect モジュールの getmembers() でインスタンスの全メンバを取得してますが、_Test__member、_Test__privateMethod が存在していることが確認できますね。

・29.12. inspect — 活動中のオブジェクトの情報を取得する — Python 3.4.3 ドキュメント
http://docs.python.jp/3.4/library/inspect.html#inspect.getmembers


以上になります。

[ 環境情報 ]
Windows 7 SP1
Python 3.4.3