この記事は3年以上前に書かれた記事で内容が古い可能性があります
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
ポリモーフィズムによって、行数増えてるじゃん、とも思うが、
オブジェクト指向プログラミングでは、保守性が重要なので、こちらの方が良いらしい
以上。
