Pythonでポリモーフィズムを理解する〜オブジェクト指向でなぜつくるのかを読んで〜
オブジェクト指向でなぜつくるのか 第2版を読んでの話の続き
参考:Pythonで、グローバル変数、インスタンス変数、ローカル変数のスコープをざっくり理解する〜オブジェクト指向でなぜつくるのかを読んで〜
イントロ
オブジェクト指向の三大要素として、「カプセル化」「継承」「ポリモーフィズム」の三つがある
カプセル化 → わかる
継承 → わかる
ポリモーフィズム → …???
ポリモーフィズムだけ読んでも理解できず、ネットで検索
色々な記事を読んでも、「ポリモーフィズムは多様性だ!」というキーワード以外は、記事によって言っていることがバラバラに思え、
理解にすこぶる時間がかかったので、この記事では違った視点で理解した内容をメモ
なぜポリモーフィズムが必要なのか
次は本題のポリモーフィズムの話
ポリモーフィズムは、サブルーチンとは逆で、異なる処理の呼び出し方をまとめる、という考え方
例えば、このようなイケてないコードがある
% cat polymorphism_test.py #!/usr/bin/env python # coding: utf-8 # クラス1 class American(): def greeting(self,greeting): if greeting == "Hello": return "Hello" else: return "Huh?" # クラス2 class Spanish(): def greeting(self,greeting): if greeting == "Hola": return "Hola" else: return "Eh?" # クラス3 class French(): def greeting(self,greeting): if greeting == "Bonjour": return "Bonjour" else: return "Hein?" # 実行 if __name__ == "__main__": american = American() print(american.greeting("Hello")) spanish = Spanish() print(spanish.greeting("Hola")) french = French() print(french.greeting("Bonjour"))
実行結果は以下の通り
% python polymorphism_test.py Hello Hola Bonjour
これの何が問題かというと、呼び出し方がスマートではない
具体的にはこの部分
# 実行 if __name__ == "__main__": american = American() print(american.greeting("Hello")) spanish = Spanish() print(spanish.greeting("Hola")) french = French() print(french.greeting("Bonjour"))
このバラバラの呼び出し方を統一するのがポリモーフィズム
どのクラスの中にも同じ「greeting」というメソッドがあるが、
以下のように、どれも「greeting_people()」関数で呼び出せることを目指す
# 実行 if __name__ == "__main__": american = American("Hello") print(greeting_people(american)) spanish = Spanish("Hola") print(greeting_people(spanish)) french = French("Bonjour") print(greeting_people(french))
ポリモーフィズムを使った解決法
では、呼び出し方を統一するにはどうすれば良いか
まずは、バラバラ存在するクラスたちを「親クラス」の元にまとめる
先ほどのコードでは、親クラスが存在しなかったので、「People()」というクラスを作成する
class People():
子クラスは、引数に親クラスの名前を書いておく
class American(People):
全体イメージは以下
# 親クラス class People(): # 処理は省略 # 子クラス1 class American(People): # 処理は省略 # 子クラス2 class Spanish(People): # 処理は省略 # 子クラス3 class French(People): # 処理は省略
次に、呼び出し方を統一するための関数を作る
それぞれのクラスの「greeting()」メソッドを呼び出していたのを、「greeting_people()」関数で呼び出せるようにする
具体的な書き方は以下の通り。「obj」の部分は何でも良い
# 呼び出し方を統一 def greeting_people(obj): return obj.greeting()
コード全体は以下の通り
% cat polymorphism_test.py #!/usr/bin/env python # coding: utf-8 # 親クラス class People(): def __init__(self, greeting): self._greeting = greeting def greeting(self): if self._greeting == "Hello": return "Hi" else: return "What?" # 子クラス1 class American(People): def greeting(self): if self._greeting == "Hello": return "Hello" else: return "Huh?" # 子クラス2 class Spanish(People): def greeting(self): if self._greeting == "Hola": return "Hola" else: return "Eh?" # 子クラス3 class French(People): def greeting(self): if self._greeting == "Bonjour": return "Bonjour" else: return "Hein?" # 呼び出し方を統一 def greeting_people(obj): return obj.greeting() # 実行 if __name__ == "__main__": american = American("Hello") print(greeting_people(american)) spanish = Spanish("Hola") print(greeting_people(spanish)) french = French("Bonjour") print(greeting_people(french))
実行結果
% python polymorphism_test.py Hello Hola Bonjour
ポリモーフィズムによって、行数増えてるじゃん、とも思うが、
オブジェクト指向プログラミングでは、保守性が重要なので、こちらの方が良いらしい
以上。