実行環境 Python3系
雑だけど、以下みたいなコードがあったとする。
test.py
class Hoge(object):
def __foo(self):
print("call foo")
class Hogehoge(Hoge):
def meta(self):
self.__foo()
h = Hogehoge()
h.meta()
HogehogeでHogeを継承して(meta)で親クラスの(__foo)を呼び出している。
この結果はこうなる。
$ python3 test.py
Traceback (most recent call last):
File "test.py", line 10, in <module>
h.meta()
File "test.py", line 7, in meta
self.__foo()
AttributeError: 'Hogehoge' object has no attribute '_Hogehoge__foo'
(_Hogehoge__foo)って名前の属性はねえよってことらしい。
(_Hogehoge__foo)ってなんだ?呼びたかったのは(__foo)のはずでは?
アンダースコアが頭に2個つく属性はマングリングされる
マングリングされると属性名の前に(_クラス名)が付与される。
つまりHoge内では(__foo)は(_Hoge__foo)にマングリングされ、
Hogehoge内では(__foo)は(_Hogehoge__foo)とマングリングされる。
なぜそのような挙動になるのかはPythonのドキュメントに書いてある。
9. クラス — Python 3.7.3 ドキュメント
ややこしいのだが、Hogehoge内で(__foo)と表記しているため、(_Hogehoge__foo)を呼び出そうとして、ないやんけって怒られていたのである。
以下のように親クラス名でマングリングされた属性名で呼べばアクセスすることができる。
test.py
class Hoge(object):
def __foo(self):
print("call foo")
class Hogehoge(Hoge):
def meta(self):
self._Hoge__foo() #<=ここが変わった
h = Hogehoge()
h.meta()
$ python3 test.py
call foo
オーバーライドはこう
ちなみに、マングリングされた親メソッドをオーバーライドしたい時もこう書ける。
test.py
class Hoge(object):
def __foo(self):
print("call foo")
class Hogehoge(Hoge):
def meta(self):
self._Hoge__foo()
def _Hoge__foo(self):
print("child call foo")
h = Hogehoge()
h.meta()
pipでインストールしたモジュールを無理やりオーバーライドしてカスタマイズしようとした時にこれで躓いた。
タイトルも微妙だし、理解はあってるか怪しいけどとりあえずこれで解決できます。
以上。