LoginSignup
0
0

More than 3 years have passed since last update.

頭にアンダースコアが2つ付くメソッドを呼び出せなくて悩まされた。

Last updated at Posted at 2019-06-20

実行環境 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でインストールしたモジュールを無理やりオーバーライドしてカスタマイズしようとした時にこれで躓いた。

タイトルも微妙だし、理解はあってるか怪しいけどとりあえずこれで解決できます。

以上。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0