6.11 ダックタイピング
Pythonは、クラスの種類に関わらず、異なるオブジェクトに対して同じ操作を適用できる「ポリモーフィズム(多態性、多様性)」の緩やかな実装を持っています。
伝統的なポリモーフィズム
Section titled “伝統的なポリモーフィズム”まずは、オブジェクト指向言語における伝統的なポリモーフィズムを見てみましょう。
同じ親クラス(Quote)を共有する3つのクラスを定義し、それぞれのクラスで says() メソッドが異なる記号(.、?、!)を返すようにします。
# 親クラスclass Quote(): def __init__(self, person, words): self.person = person self.words = words def who(self): return self.person def says(self): return self.words + '.'
# 子クラス1: 疑問符を返すclass QuestionQuote(Quote): def says(self): return self.words + '?'
# 子クラス2: 感嘆符を返すclass ExclamationQuote(Quote): def says(self): return self.words + '!'これらのクラスからオブジェクトを作り、同じメソッドを呼び出すと、クラスごとに異なる動作(戻り値)を提供します。
hunter = Quote('Elmer Fudd', "I'm hunting wabbits")print(hunter.who(), 'says:', hunter.says())# 出力: Elmer Fudd says: I'm hunting wabbits.
hunted1 = QuestionQuote('Bugs Bunny', "What's up, doc")print(hunted1.who(), 'says:', hunted1.says())# 出力: Bugs Bunny says: What's up, doc?
hunted2 = ExclamationQuote('Daffy Duck', "It's rabbit season")print(hunted2.who(), 'says:', hunted2.says())# 出力: Daffy Duck says: It's rabbit season!Pythonにおけるダックタイピング
Section titled “Pythonにおけるダックタイピング”Pythonはそこからさらに一歩進んで、 「必要なメソッド(この場合は who() と says())を持ちさえすれば、継承関係が全くない無関係なオブジェクトであっても、同じように扱える」 という特徴があります。
先ほどの猟師や獲物のクラスとは全く無関係な、小川のせせらぎを表す BabblingBrook クラスを作ってみましょう。
# Quoteクラスを継承していない、全く無関係なクラスclass BabblingBrook(): def who(self): return 'Brook' def says(self): return 'Babble'
brook = BabblingBrook()ここで、どんなオブジェクトでも受け取って who() と says() を実行する共通の関数 who_says() を作ります。
def who_says(obj): print(obj.who(), 'says', obj.says())
# Quoteの子孫オブジェクトを渡すwho_says(hunter) # Elmer Fudd says I'm hunting wabbits.who_says(hunted1) # Bugs Bunny says What's up, doc?
# 全く無関係なBrookオブジェクトを渡しても、正常に動作するwho_says(brook) # Brook says Babble