Pythonのプライベートメンバは実はブライベートじゃない
Pythonのクラスでプライベートメンバを表現するときにメンバ名の先頭に__
(アンダースコア*2)を利用しますが、実は全然プライベートじゃないというお話です。
Pythonの一般的なプライベートの表現
試しに、Bank
クラスを作ってみようと思います。
class Bank:
def __init__(self, name):
self.name = name
self.__amount = 0
def deposit(self, amount):
self.__amount += amount
def withdraw(self, amount):
self.__amount -= amount
超しょぼい銀行になりました。
__amount
はプライベートメンバにしたので外からアクセスしようとすると
bank = Bank("エンジニアもどきの銀行")
print(bank.__amount)
# AttributeError: 'Bank' object has no attribute '__amount'
となってアクセスできません。
実はプライベートじゃない
ここからが本題です。
Pythonで__
をつけて宣言したメンバは実はプライベートでもなんでもなく、ただ名前が変わっているだけなのです。
どんな名前に変わっているのかというと_クラス名__メンバ名
になっています。
先ほどのBank
クラスの場合、
bank = Bank("エンジニアもどきの銀行")
bank._Bank__amount += 100
print(bank._Bank__amount)
# 100
こんな感じでアクセスできてしまします。
全くプライベートではありません。
dir(bank)
['_Bank__amount', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__',
'__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'deposit', 'name', 'withdraw']
こんな感じで、ちゃんと属性名の一覧にも名前が変わった後の'_Bank__amount'
が入っています。
ただ、名前が変わるだけでも、表面的にはプライベートメンバっぽく振る舞えるので実用上では、そこまで支障が出ないらしいです。