Python で Template Method パターンを使うためにプライベートメソッドをオーバーライドして基底クラスから呼ぼうとしたところ、基底クラスのメソッドがよばれるという現象にいきあたりました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class Base(): def hoge(self): self.__private_method() def __private_method(self): print('this is Base class') class Derived(Base): def __private_method(self): print('this is Derived class') d = Derived() d.hoge() # "this is Base class" |
パブリックメソッドなら派生クラスのメソッドがよばれます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class Base(): def hoge(self): self.public_method() def public_method(self): print('this is Base class') class Derived(Base): def public_method(self): print('this is Derived class') d = Derived() d.hoge() # "this is Derived class" |
こうなる原因は Python のプライベートメソッドが本当にプライベートではなくメソッド名をマングリングしているだけだからです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import re class Base(): def hoge(self): self.__private_method() def __private_method(self): print('this is Base class') class Derived(Base): def __private_method(self): print('this is Derived class') d = Derived() # 組み込みメソッド以外を抽出 methods = [m for m in dir(d) if re.search('__.+__', m) is None] print(methods) # ['_Base__private_method', '_Derived__private_method', 'hoge'] |
つまり、Base クラスにて __private_method と記述するとそれは _Base__private_method と読み替えられます。
__private_method をよんでいるつもりが _Base__private_method をよんでいるため、派生クラスのプライベートメソッド _Derived__private_method がよばれることはありません。
結論としては Python ではプライベートメソッドはオーバーライドできないということになります。Template Method パターンを使う場合は抽象メソッドはパブリックメソッドで作成することになります。