ポリモーフィズムは、異なる構造を持つオブジェクトが同じインターフェースを実装し、相互に置き換え可能にするオブジェクト指向プログラミングの基本原則です。Pythonでは動的型付けにより、ポリモーフィズムは非常に柔軟に実装されています。
厳密な静的型付けを持つ言語(Java、C++)では、ポリモーフィズムをサポートするためにインターフェースや抽象クラスの宣言が必要です。しかし、Pythonではダックタイピングのおかげで、ポリモーフィズムは継承の階層やインターフェースに依存していません。重要なのは、オブジェクトが必要なメソッドや属性をサポートしていることです。
一方で、これにより言語は柔軟かつ便利になりますが、もう一方では、タイプミスや必要なメソッドの欠如に起因する実行時エラーの可能性が高まります。これらのエラーは、コードが実行されるまで現れません。
Pythonには以下の種類があります:
class Animal: def speak(self): raise NotImplementedError class Dog(Animal): def speak(self): return 'Woof!' class Cat(Animal): def speak(self): return 'Meow!' def animal_voice(animal): print(animal.speak()) animal_voice(Dog()) # Woof! animal_voice(Cat()) # Meow!
class Duck: def quack(self): return 'Quack!' def make_quack(animal): print(animal.quack()) make_quack(Duck()) # Quack!
主な特徴:
Pythonでポリモーフィズムを保証する唯一の方法は継承ですか?
いいえ。ダックタイピングのおかげで、関数はそのクラスや階層に関係なく、必要なメソッドを持つオブジェクトを受け入れることができます。
メソッドの名前だけでシグネチャが一致することはポリモーフィズムと見なされますか?
いいえ。オブジェクトが必要なメソッドをサポートしていても、その意味が期待されたものと異なる場合、バグが発生する可能性があります。ポリモーフィズムは、インターフェースだけでなく、その意味が一致する場合にのみ成功します。
抽象クラスは、子クラスでの不正なインターフェース実装からのエラーを防ぎますか?
部分的にのみです。継承者が抽象メソッドを実装しない場合、インスタンスを作成しようとするとTypeErrorが発生します。しかし、ロジックを違反して実装した場合はエラーが発生する可能性があります。
ログ記録ライブラリに、log()メソッドがある外部クラスを導入しますが、オブジェクトデータを返すだけでログに記録しません。エラーは運用中にのみ現れます。
メリット:
デメリット:
クラスにはテストが付随し、インターフェースは抽象基本クラスと@abstractmethodを通じて形式化され、ドキュメントにメソッドの意味が記載されています。
メリット:
デメリット: