記事内にはプロモーションが含まれています

【Python】ポリモーフィズムとは?3つの実装例をコード付きで徹底解説

【Python】ポリモーフィズムとは?3つの実装例をコード付きで徹底解説 プログラミングの疑問解決
「Pythonでオブジェクト指向を学んでいるけれど、ポリモーフィズムがいまいちピンとこない」
「継承と何が違うの? ダックタイピングって何?」

Python学習中の多くの方がつまずくのが、この「ポリモーフィズム(多態性)」という概念です。

言葉自体が難しそうに聞こえますが、実はPythonを使っていると無意識のうちに恩恵を受けている非常に身近で便利な機能です。

ポリモーフィズムを理解して使いこなせれば、「修正に強く、拡張しやすいコード」が書けるようになります。
逆にポリモーフィズムを知らないと、if文だらけの読みづらいコードになりがちです。

この記事では、Pythonにおけるポリモーフィズムの基本概念から、実務で使える3つの実装例(継承、ダックタイピング、抽象基底クラス)まで、最新のベストプラクティスを交えて初心者向けにわかりやすく解説します。

【著者プロフィール&本記事の信頼性】
プロフィール
  • 著者は元エンジニア
  • 大手プログラミングスクールのWebディレクター兼 ライターを経験
  • 自らも地元密着型のプログラミングスクールを運営
プロフィール詳細はコチラ
当ブログ著者
当ブログ著者
忖度は一切なし!
本気で未経験からエンジニア転職を目指すなら、
日本最大級の比較サイト「マイベスト」で【4年連続人気NO.1】となった
RUNTEQ(ランテック)一択!
【RUNTEQの特徴】
✅受講生からの評判が驚くほど良い
✅学習はハードだが未経験とは思えないほど高いスキルが身に付く
挫折させない万全なサポート体制が用意されている
✅採用面接で担当者に刺さるレベルの高い「ポートフォリオ」を作成できる
✅給付金を使えば実質約13万円という格安料金で受講できる

\ もちろん勧誘行為は一切なし! 相談だけでもOK! /

ポリモーフィズム(多態性)とは?わかりやすく解説

ポリモーフィズム(Polymorphism)とは、直訳すると「多態性(たたいせい)」や「多様性」という意味になります。
プログラミングにおいては、「異なる種類のオブジェクトを、同じ操作(メソッド)で扱うこと」を指します。

もっと平たく言うと、「相手が誰であれ、『挨拶して』と頼めば、その人なりの挨拶をしてくれる」という仕組みのことです。

現実世界で例えると?

例えば、あなたの目の前に「日本人」「アメリカ人」「中国人」の3人がいるとします。

あなたが彼ら全員に対し、共通の命令として「挨拶をして」と伝えたとしましょう。

  • 日本人は、「こんにちは」とお辞儀をします。
  • アメリカ人は、「Hello」と手を振ります。
  • 中国人は、「ニーハオ」と微笑みます。

あなたは「挨拶をして」というたった一つの共通の命令を出しただけですが、相手(オブジェクト)の種類によって、返ってくる反応(振る舞い)は異なります。
これがポリモーフィズムです。

もしポリモーフィズムがなかったら、「もし相手が日本人なら『挨拶して』と言う」「もし相手がアメリカ人なら『Greet me』と言う」・・・といったように、相手に合わせて命令を変えなければならず、非常に面倒です。

Pythonでポリモーフィズムを実現する3つの方法

Pythonでこのポリモーフィズムを実現するには、主に3つのアプローチがあります。

  1. 継承とメソッドオーバーライド(伝統的なオブジェクト指向)
  2. ダックタイピング(Pythonらしい柔軟な方法)
  3. 抽象基底クラス (ABC)(型安全性を高める方法)

それぞれの書き方と特徴を、具体的なコード例で見ていきましょう。

1. 継承とメソッドオーバーライド

親クラス(スーパークラス)で共通のメソッド名を定義し、子クラス(サブクラス)でその中身を上書き(オーバーライド)する方法です。

他の静的型付け言語(JavaやC++など)でも一般的なスタイルです。

class Animal:
    def speak(self):
        pass

class Dog(Animal):
    def speak(self):
        return "ワンワン!"

class Cat(Animal):
    def speak(self):
        return "ニャー!"

class Cow(Animal):
    def speak(self):
        return "モー!"

# 動物たちをリストにまとめる
animals = [Dog(), Cat(), Cow()]

# どの動物がきても「speak()」だけで鳴かせることができる
for animal in animals:
    print(animal.speak())

# 出力結果:
# ワンワン!
# ニャー!
# モー!

ここでは animals リストの中身が Dog なのか Cat なのかを気にする必要はありません。

すべてのクラスが speak() メソッドを持っていることが保証されているため、ループ処理でまとめて扱うことができます。

2. ダックタイピング(Duck Typing)

Pythonにおいて最も特徴的で、よく使われるのが「ダックタイピング」です。
「アヒルのように歩き、アヒルのように鳴くなら、それはアヒルだ」という格言に由来します。

クラスの継承関係(親子関係)は問いません。
単に「同じ名前のメソッドを持っているか?」だけを重視します。

class Car:
    def move(self):
        print("車が道路を走ります")

class Boat:
    def move(self):
        print("ボートが水面を進みます")

class Plane:
    def move(self):
        print("飛行機が空を飛びます")

# まったく関係ないクラス同士だが、「move」メソッドを持っている点は同じ
vehicles = [Car(), Boat(), Plane()]

def start_journey(vehicle):
    # 相手がCarかBoatか継承関係などは気にしない
    # 「move」さえできれば何でもいい
    vehicle.move()

for v in vehicles:
    start_journey(v)

# 出力結果:
# 車が道路を走ります
# ボートが水面を進みます
# 飛行機が空を飛びます

ダックタイピングのメリットは、「クラス設計が柔軟になり、コードがシンプルになること」と、「継承のしがらみに縛られず、他人が作ったクラスでもメソッド名さえ合えば流用できること」です。

デメリットは、「実行するまでエラー(メソッドが存在しないなど)がわからない場合があること」です。

3. 抽象基底クラス (Abstract Base Classes)

大規模な開発や、複数人でコードを書く場合、「メソッドの実装を強制したい(書き忘れを防ぎたい)」というニーズが出てきます。

そんな時は、Python標準ライブラリ abc モジュールを使って抽象基底クラスを定義します。

from abc import ABC, abstractmethod

# 抽象クラス(設計図のようなもの)
class PaymentProcessor(ABC):
    @abstractmethod
    def pay(self, amount):
        pass

# クレジットカード決済
class CreditCardPayment(PaymentProcessor):
    def pay(self, amount):
        print(f"クレジットカードで {amount}円 支払いました。")

# PayPay決済
class PayPayPayment(PaymentProcessor):
    def pay(self, amount):
        print(f"PayPayで {amount}円 支払いました。")

# 銀行振込(payメソッドを書き忘れたとする)
# class BankTransferPayment(PaymentProcessor):
#     pass 
# → これを実行しようとすると、「payメソッドが実装されていません」とエラーになるため、実装漏れを防げる

payments = [CreditCardPayment(), PayPayPayment()]

for p in payments:
    p.pay(1000)

# 出力結果:
# クレジットカードで 1000円 支払いました。
# PayPayで 1000円 支払いました。

PaymentProcessor を継承したクラスは、必ず pay メソッドを実装しなければインスタンス化できません。

これにより、ポリモーフィズムの安全性が担保されます。

2025年のトレンド:Protocol(構造的部分型)

最近のPython(特に型ヒントを活用するモダンな開発)では、typing.Protocol を使った手法も人気です。

これは、ダックタイピングの柔軟さと、ABCの型安全性をいいとこ取りしたような機能です。

継承を明示しなくても、「特定のメソッドを持っているクラス」であることを型チェッカー(mypyなど)に認識させることができます。

from typing import Protocol

# 「fly」メソッドを持つものは何でも「Flyable」とみなす
class Flyable(Protocol):
    def fly(self) -> None:
        ...

class Bird:
    def fly(self):
        print("鳥が飛びます")

class Drone:
    def fly(self):
        print("ドローンが飛びます")

def make_it_fly(obj: Flyable):
    obj.fly()

# 継承していなくても、flyメソッドがあればOK(静的解析でチェック可能)
make_it_fly(Bird())
make_it_fly(Drone())

Pythonでポリモーフィズムを使うメリット

では、なぜわざわざポリモーフィズムのような仕組みを使うのでしょうか?
そのメリットについて紹介します。

 if文やswitch文を減らせる(コードの簡略化)

ポリモーフィズムを使わない場合、「もし犬ならワン、もし猫ならニャー……」という条件分岐を延々と書く必要があります。
動物の種類が増えるたびに、メインのコードを修正しなければなりません。

ポリモーフィズムを使えば、新しい動物クラスを追加するだけで済み、メインのコード(animal.speak())は一切変更する必要がありません。

拡張性と保守性の向上(疎結合)

メインの処理と、個々のオブジェクトの処理を切り離すことができます。

これにより、機能追加やバグ修正の影響範囲を最小限に抑えることができ、大規模なアプリケーションでもメンテナンスが容易になります。

Pythonのポリモーフィズムに関するよくある質問

ここでは、Pythonのポリモーフィズムに関するよくある質問について回答していきます。

Pythonではインターフェース(interface)は使わないのですか?

Javaのような interface キーワードはありません。
代わりに、前述の「抽象基底クラス (ABC)」や「Protocol」がその役割を果たします。

また、ダックタイピング文化が強いため、厳密なインターフェース定義をせずに実装することも多々あります。

初心者はどの方法から覚えるべきですか?

まずは「ダックタイピング」の概念を理解するのがおすすめです。
理由は、「Pythonらしさを最も体感できるから」です。

「継承関係がなくても、同じメソッド名なら同じように扱える」という感覚を掴みましょう。

初心者がPythonのポリモーフィズムについて効率的に学ぶには

PythonのポリモーフィズムをはじめとするPythonの知識・スキルを効率的に習得するには、プログラミングスクールの活用が最も近道です。

スクールでスキルを高めることにより、今の仕事に活かしたり、副業として高単価な案件を受注できたりするだけでなく、Pythonエンジニアとして転職することも可能になります。

Pythonエンジニアは需要が非常に高いため、それに比例して年収も高くなる傾向にあります。
「今よりも年収を上げたい」「将来性の高い職種であるエンジニアへ転職したい」といった気持ちが強い場合は、プログラミングスクールでPythonの専門スキルを習得しつつ、ポートフォリオ支援や転職支援を受けてエンジニアへ転職する、という道を目指すのもよいでしょう。

なお、「Pythonに強く、受講生からの評判も良いプログラミングスクール」には、以下のようなところがあります。

その他、以下の記事でもPythonのおすすめスクールをまとめていますので、興味のある方は是非参考にしてください。