<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>「構造的部分型」タグの記事一覧Python Tech</title>
	<atom:link href="https://tech.nkhn37.net/tag/%E6%A7%8B%E9%80%A0%E7%9A%84%E9%83%A8%E5%88%86%E5%9E%8B/feed/" rel="self" type="application/rss+xml" />
	<link>https://tech.nkhn37.net</link>
	<description>Python学習サイト</description>
	<lastBuildDate>Sat, 15 Nov 2025 22:01:47 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://tech.nkhn37.net/wp-content/uploads/2021/01/cropped-lion-normal-clear-1-32x32.png</url>
	<title>「構造的部分型」タグの記事一覧Python Tech</title>
	<link>https://tech.nkhn37.net</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>【Python】ポリモーフィズムの実現方法</title>
		<link>https://tech.nkhn37.net/python-class-polymorphism/</link>
					<comments>https://tech.nkhn37.net/python-class-polymorphism/#respond</comments>
		
		<dc:creator><![CDATA[naoki-hn]]></dc:creator>
		<pubDate>Mon, 08 Feb 2021 00:00:00 +0000</pubDate>
				<category><![CDATA[クラス]]></category>
		<category><![CDATA[abc]]></category>
		<category><![CDATA[protocol]]></category>
		<category><![CDATA[typing]]></category>
		<category><![CDATA[インターフェース]]></category>
		<category><![CDATA[ポリモーフィズム]]></category>
		<category><![CDATA[抽象クラス]]></category>
		<category><![CDATA[抽象メソッド]]></category>
		<category><![CDATA[構造的部分型]]></category>
		<guid isPermaLink="false">https://tech.nkhn37.net/?p=802</guid>

					<description><![CDATA[Python におけるポリモーフィズムの実現方法について解説します。 ポリモーフィズム（polymorphism） クラス実装において、異なるクラスが共通のインターフェース（メソッドやプロパティ）を実装し、同じメソッド名 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>Python における<span class="jinr-d--text-color d--marker1 d--bold">ポリモーフィズムの実現方法</span>について解説します。</p>



<h2 class="wp-block-heading jinr-heading d--bold" id="ポリモーフィズム-polymorphism">ポリモーフィズム（polymorphism）</h2>



<p>クラス実装において、異なるクラスが共通のインターフェース（メソッドやプロパティ）を実装し、同じメソッド名で異なる振る舞いをすることを<span class="jinr-d--text-color d--marker1 d--bold">ポリモーフィズム（多様性・多相性）</span>と言います。</p>



<p>Python では、ポリモーフィズムを実現する手法として、以下の ２ つのアプローチがあります。</p>



<ol class="wp-block-list jinr-list">
<li>抽象クラスの継承：<code><span class="jinr-d--text-color d--marker1 d--bold">abc.ABC</span></code> によるポリモーフィズム</li>



<li>構造的部分型：<code><span class="jinr-d--text-color d--marker1 d--bold">typing.Protocol</span></code> によるポリモーフィズム</li>
</ol>



<p>この記事では、Python でポリモーフィズムを実現する方法を紹介します。</p>



<h2 class="wp-block-heading jinr-heading d--bold" id="抽象クラス-抽象メソッド">抽象クラスの継承：<code>abc.ABC</code></h2>



<p>以降では、<code>Person</code>、<code>Teacher</code>、<code>Doctor</code> クラスを用いてポリモーフィズムを考えていきます。まずは、継承をベースにした考え方について見ていきましょう。以下は、<code>Person</code>、<code>Teacher</code>、<code>Doctor</code> クラスの継承関係を表した図です。</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img fetchpriority="high" decoding="async" width="1024" height="631" src="https://tech.nkhn37.net/wp-content/uploads/2021/02/image-2-1024x631.png" alt="python ポリモーフィズム" class="wp-image-877" srcset="https://tech.nkhn37.net/wp-content/uploads/2021/02/image-2-1024x631.png 1024w, https://tech.nkhn37.net/wp-content/uploads/2021/02/image-2-300x185.png 300w, https://tech.nkhn37.net/wp-content/uploads/2021/02/image-2-768x473.png 768w, https://tech.nkhn37.net/wp-content/uploads/2021/02/image-2.png 1157w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p><code>mywork</code> メソッドは、仕事の内容を出力するメソッドです。しかし、同じ <code>mywork</code> メソッドであっても、<code>Teacher</code> クラスでは教える仕事、<code>Doctor</code> クラスでは診察する仕事であることを説明するように出力の振る舞いを変えたいとします。</p>



<p>このような際にはメソッドの<span class="jinr-d--text-color d--marker1 d--bold">オーバーライド</span>を行います。オーバーライドは「<a href="https://tech.nkhn37.net/python-class-inheritance/" target="_blank" rel="noreferrer noopener">クラスの継承の基本</a>」を参考にしてください。オーバーライドは、任意でメソッドの挙動を変更する仕組みですが、派生クラスでメソッドの実装を強制することまではできません。</p>



<p>派生クラスでのメソッドの実装を強制したい場合は「<span class="jinr-d--text-color d--marker1 d--bold">抽象クラス</span>」「<span class="jinr-d--text-color d--marker1 d--bold">抽象メソッド</span>」を使用します。抽象クラスはインスタンス化できないクラスであり、クラス設計の構造を提供します。抽象メソッドは、抽象クラスを継承する派生クラスが具体的に実装を行う必要があるメソッドのことを言います。</p>



<p>抽象クラスを継承したクラスは、抽象メソッドを実装しない限りインスタンス化できません。そのため、抽象クラスを利用することで、派生クラスに共通のインターフェース（メソッド構造）を強制でき、設計上の一貫性や拡張性を保つことができます。</p>



<p>抽象クラスや抽象メソッドは、ポリモーフィズムを活かしたインターフェース設計に欠かせない概念です。</p>



<h3 class="wp-block-heading jinr-heading d--bold"><code>abc</code> モジュールを用いた抽象クラス・抽象メソッドの実装</h3>



<p>Python では、抽象クラスと抽象メソッドを実現するために <span class="jinr-d--text-color d--marker1 d--bold"><code>abc</code></span> モジュールが使用できます。<code>abc</code> とは「<span class="jinr-d--text-color d--marker1 d--bold">abstract base class</span>」の略です。</p>



<p>以下の例は、<code>abc</code> モジュールを使用して抽象クラス、抽象メソッドを定義しています。</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import abc


class Person(abc.ABC):
    def __init__(self, name: str) -> None:
        self.__name = name

    @property
    def name(self) -> str:
        return self.__name

    @name.setter
    def name(self, value: str) -> None:
        self.__name = value

    def say_myname(self) -> None:
        print(f"私の名前は、{self.__name}です。")

    @abc.abstractmethod
    def mywork(self) -> None:
        ...
        # pass でもよい


class Teacher(Person):
    def __init__(self, name: str, subject: str) -> None:
        super().__init__(name)
        self.__subject = subject

    @property
    def subject(self) -> str:
        return self.__subject

    @subject.setter
    def subject(self, value: str) -> None:
        self.__subject = value

    def mywork(self) -> None:
        print(f"私の仕事は、{self.__subject}の教師です。")


class Doctor(Person):
    def __init__(self, name: str, medical_speciality: str) -> None:
        super().__init__(name)
        self.__medical_speciality = medical_speciality

    @property
    def medical_speciality(self) -> str:
        return self.__medical_speciality

    @medical_speciality.setter
    def medical_speciality(self, value: str) -> None:
        self.__medical_speciality = value

    def mywork(self) -> None:
        print(f"私の仕事は、{self.__medical_speciality}の医者です。")


def introduction(person: Person) -> None:
    """Person 型の引数を受け取る"""
    print("=== introduction ===")
    person.say_myname()
    person.mywork()


def main():
    person1 = Teacher("田中太郎", "英語")
    person1.mywork()
    introduction(person1)

    print("==================================")

    person2 = Doctor("鈴木一郎", "内科")
    person2.mywork()
    introduction(person2)


if __name__ == "__main__":
    main()</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">【実行結果】
私の仕事は、英語の教師です。
=== introduction ===
私の名前は、田中太郎です。
私の仕事は、英語の教師です。
==================================
私の仕事は、内科の医者です。
=== introduction ===
私の名前は、鈴木一郎です。
私の仕事は、内科の医者です。</pre>



<p>上記例での <code>Person</code>クラスは <span class="jinr-d--text-color d--marker1 d--bold"><code>abc.ABC</code></span> クラスを継承することで抽象クラスになります。<code>mywork</code> メソッドは <span class="jinr-d--text-color d--marker1 d--bold"><code>@abc.abstractmethod</code></span> デコレータで付けることで抽象メソッドとなり、これによりサブクラスで必ず実装されることを要求します。</p>



<p>抽象メソッドの定義では、継承したクラス側で実装をするため中身は不要で「<code>...</code>」と記載しておきます。書籍やブログなどでは「<code>pass</code>」と記載している例がありますが、 もちろん <code>pass</code> でも問題ありません。ただし、モダンな Python では「<code>...</code>」と書くのが一般的になってきています。</p>



<p><code>Teacher</code> クラスと <code>Doctor</code> クラスは <code>Person</code> を継承し、<code>mywork</code> メソッドをオーバーライドします。もし、<code>Doctor</code> クラスで <code>mywork</code> メソッドの実装を忘れると、以下のようなエラーが発生します。</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">【実行結果例】
Traceback (most recent call last):
...(省略)...
TypeError: Can't instantiate abstract class Doctor with abstract methods mywork</pre>



<p>このように <code>abc</code> モジュールを活用することで、抽象メソッドの実装を強制し、ポリモーフィズムを実現できます。</p>



<p>抽象クラスにおけるこの特徴は、インターフェース（共通の振る舞い）を定義する際に非常に重要な意味を持ちます。以下の <code>introduction</code> 関数は <code>Person</code> を引数に取る関数です。しかし、呼び出し時には <code>Teacher</code> や <code>Doctor</code> クラスのインスタンスを受け取ることができていることが分かります。</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">def introduction(person: Person) -> None:
    """Person 型の引数を受け取る"""
    print("=== introduction ===")
    person.say_myname()
    person.mywork()</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="4,10" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">def main():
    person1 = Teacher("田中太郎", "英語")
    person1.mywork()
    introduction(person1)

    print("==================================")

    person2 = Doctor("鈴木一郎", "内科")
    person2.mywork()
    introduction(person2)</pre>



<p>このように「共通の型に基づいて異なるクラスを同じように扱う」ことが可能になる点は、インターフェース設計の中心となる考え方です。これがまさにポリモーフィズムであり、抽象クラスが果たす重要な役割です。</p>



<h2 class="wp-block-heading jinr-heading d--bold">構造的部分型：<code>typing.Protocol</code></h2>



<p>上記では、<code>abc</code> モジュールを用いて抽象クラスを継承し、サブクラスごとにメソッドを実装させることでポリモーフィズムを実現する方法を紹介しました。</p>



<p>近年では、もう 1 つのポリモーフィズムの実現方法として <code><span class="jinr-d--text-color d--marker1 d--bold">typing.Protocol</span></code> を使用した方法も広く利用されており、Python における強力なインターフェース手法となっています。</p>



<p>この方法は <code>abc</code> による手法と異なり「<span class="jinr-d--text-color d--marker1 d--bold">クラスの継承が不要</span>」である点が大きな特徴です。まずは、<code>Protocol</code> のベースとなる考え方を説明し、具体的な実装方法を見ていきましょう。</p>



<h3 class="wp-block-heading jinr-heading d--bold">構造的部分型（Structural Subtyping）</h3>



<p>まずは、Protocol の基盤となる考え方である「<span class="jinr-d--text-color d--marker1 d--bold">構造的部分型（Structural Subtyping）</span>」について説明します。</p>



<p><code>abc.ABC</code> を用いた抽象クラスでは、親クラス（抽象クラス）を継承し、抽象メソッドをオーバーライドすることでポリモーフィズムを実現します。一方で、<code>Protocol</code> が採用しているのは構造的部分型という考え方です。</p>



<p>構造的部分型とは「<span class="jinr-d--text-color d--marker1 d--bold">クラス継承をしていなくても、必要なメソッド・プロパティを持っていれば、その型として扱ってよい</span>」という仕組みであり、Python がもともと持っているダックタイピングと非常に相性が良い手法です。</p>



<p>例えば、 <code>Person</code> と <code>Teacher</code>、<code>Doctor</code> の例に当てはめてみると、以下の特徴を持つクラスは<span class="jinr-d--text-color d--marker1 d--bold">継承していなくても</span> <code>Person</code> 型であると扱うことができます。</p>



<section class="wp-block-jinr-blocks-simplebox b--jinr-block-container"><div class="b--jinr-block b--jinr-box d--simple-box1  "><div class="c--simple-box-inner">
<ul class="wp-block-list jinr-list">
<li><code>name</code> プロパティ</li>



<li><code>say_myname</code> メソッド</li>



<li><code>mywork</code> メソッド</li>
</ul>
</div></div></section>



<h3 class="wp-block-heading jinr-heading d--bold"><code>typing.Protocol</code> による実装</h3>



<p>以下で、具体的な実装例を用いて <code>Protocol</code> の理解を深めましょう。以下は、<code>abc.ABC</code> を用いた方法と出力結果自体は同じですが、背後にある考え方は異なるため説明をしていきます。</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">from typing import Protocol


# Protocol: 構造的部分型を使ったインターフェース
class Person(Protocol):
    @property
    def name(self) -> str: ...

    @name.setter
    def name(self, value: str) -> None: ...

    def say_myname(self) -> None: ...

    def mywork(self) -> None: ...


# Teacher クラス (Person は継承しない)
class Teacher:
    def __init__(self, name: str, subject: str) -> None:
        self._name = name
        self._subject = subject

    @property
    def name(self) -> str:
        return self._name

    @name.setter
    def name(self, value: str) -> None:
        self._name = value

    def say_myname(self) -> None:
        print(f"私の名前は、{self._name}です。")

    def mywork(self) -> None:
        print(f"私の仕事は、{self._subject}の教師です。")


# Doctor クラス (Person は継承しない)
class Doctor:
    def __init__(self, name: str, medical_speciality: str) -> None:
        self._name = name
        self._medical_speciality = medical_speciality

    @property
    def name(self) -> str:
        return self._name

    @name.setter
    def name(self, value: str) -> None:
        self._name = value

    def say_myname(self) -> None:
        print(f"私の名前は、{self._name}です。")

    def mywork(self) -> None:
        print(f"私の仕事は、{self._medical_speciality}の医者です。")


def introduction(person: Person) -> None:
    """Person 型の引数を受け取る"""
    print("=== introduction ===")
    person.say_myname()
    person.mywork()


def main() -> None:
    person1 = Teacher("田中太郎", "英語")
    person1.mywork()
    introduction(person1)

    print("==================================")

    person2 = Doctor("鈴木一郎", "内科")
    person2.mywork()
    introduction(person2)


if __name__ == "__main__":
    main()</pre>



<p><code>abc.ABC</code> を用いた方法と異なる点は以下の通りです。</p>



<ol class="wp-block-list jinr-list">
<li>継承が不要<br><code>Teacher</code> や <code>Doctor</code> が <code>Person</code> を継承していませんが、必要なメソッドをすべて備えているため、<code>Person</code> の構造的部分型として扱われます。そのため、<code>introduce</code> 関数に引数で渡しても問題なく動作します。</li>



<li>メソッドの実装強制は行われない<br><code>abc.ABC</code> では抽象メソッドが未実装の場合、実行時にエラーが発生しましたが、<code>Protocol</code> では、実行時に強制しません。</li>



<li><code>Protocol</code> はインターフェース定義<br><code>Protocol</code> はインターフェース定義が目的であるため、<code>abc.ABC</code> のように親クラスで共通の具体メソッドを定義し、子クラスで使うことはできません。</li>



<li>既存クラスにも後付けで適用しやすい<br>継承していない既存クラスにも、必要なメソッドを追加すれば、<code>Protocol</code> を適用できます。これは、<code>Protocol</code> の大きな利点です。</li>
</ol>



<p>このように、<code>Protocol</code> で構造的部分型に基づくポリモーフィズムを実現できます。</p>



<h2 class="wp-block-heading jinr-heading d--bold"><code>abc.ABC</code> と <code>typing.Protocol</code> の使い分け</h2>



<p>ポリモーフィズムを実現する方法として「<code>abc.ABC</code> を使用する方法」と「<code>typing.Protocol</code> で構造的部分型を使用する方法」を紹介しました。どちらの方法を使用するかは、適用ケースにより十分な検討が必要ですが、使い分けの判断材料となる考え方を紹介します。</p>



<h3 class="wp-block-heading jinr-heading d--bold">継承が必要かどうか</h3>



<p>親クラスで共通メソッドを記載したい場合や、子クラスで必ず実装させたいメソッドがある場合は、<code>ABC</code> を使用しましょう。一方で、既存クラスに後付けで「この型として扱いたい」というような場合には、メソッドの定義を追加すればよいだけですので <code>Protocol</code> の使用がおすすめです。</p>



<h3 class="wp-block-heading jinr-heading d--bold">実行時に強制させたいか</h3>



<p><code>ABC</code> では、抽象メソッドを実装していないとインスタンス化の際にエラーとなるため強制力があります。実行時の保証が必要なケースは <code>ABC</code> を使う方が良いでしょう。<code>Protocol</code> の場合は、インスタンス化する際にはチェックはされないため、開発者が十分に注意して実装する必要になります。</p>



<h3 class="wp-block-heading jinr-heading d--bold">複数の型にまたがる後付けのインターフェースが必要</h3>



<p><code>Protocol</code> は、定義したメソッドを実装しているかどうかで判断されます。そのため、ライブラリのクラスや既存コードなどに後付けでインターフェースを追加することで「この <code>Protocol</code> を満たしている」とみなすことができます。これは、<code>ABC</code> では不可能な優れた点です。</p>



<h3 class="wp-block-heading jinr-heading d--bold">設計パターンにより判断する</h3>



<p><code>ABC</code> は、オブジェクト指向ベースの設計思想です。一方で、<code>Protocol</code> は、Haskell や Rust のような型システムを重視したプログラミング言語の設計思想に近い部分があります。設計方針や思想に応じて使い分けるのもよいと思います。</p>



<h2 class="wp-block-heading jinr-heading d--bold">まとめ</h2>



<p>Python での<span class="jinr-d--text-color d--marker1 d--bold">ポリモーフィズムの実現方法</span>について解説しました。Python では、ポリモーフィズムを実現する手法として、以下の ２ つのアプローチがあります。</p>



<ol class="wp-block-list jinr-list">
<li>抽象クラスの継承：<code><span class="jinr-d--text-color d--marker1 d--bold">abc.ABC</span></code> によるポリモーフィズム</li>



<li>構造的部分型：<code><span class="jinr-d--text-color d--marker1 d--bold">typing.Protocol</span></code> によるポリモーフィズム</li>
</ol>



<p>この記事では、各方法の実装例や特徴について紹介しました。ポリモーフィズムはインターフェースの設計などにおいて非常に重要な役割を果たすものであるため、各方法についてしっかりと理解してもらえたらと思います。</p>



<section class="wp-block-jinr-blocks-iconbox b--jinr-block b--jinr-iconbox"><div class="d--simple-iconbox5 ">
			<i class="jif jin-ifont-v2speaker" aria-hidden="true"></i>
			<div class="a--jinr-iconbox">
<p><code>abc</code> の公式ドキュメントは<a href="https://docs.python.org/ja/3/library/abc.html?highlight=abc#module-abc" target="_blank" rel="noreferrer noopener">こちら</a>を参照してください。</p>



<p><code>typing</code> の公式ドキュメントは<a href="https://docs.python.org/ja/3/library/typing.html" target="_blank" rel="noreferrer noopener">こちら</a>を参照してください。</p>
</div>
		</div></section>



<section class="wp-block-jinr-blocks-simplebox b--jinr-block-container"><div class="b--jinr-block b--jinr-box d--heading-box8  "><div class="a--simple-box-title d--bold">ソースコード</div><div class="c--simple-box-inner">
<p>上記で紹介しているソースコードについては <a href="https://github.com/nkhn37/python-tech-sample-source/tree/main/python-basic/class/polymorphism" target="_blank" rel="noreferrer noopener">GitHub</a> にて公開しています。参考にしていただければと思います。</p>
</div></div></section>


<section class="b--jinr-block b--jinr-blogcard d--blogcard-hover-up d--blogcard-style1 d--blogcard-mysite t--round "><div class="a--blogcard-label ef">あわせて読みたい</div><a class="o--blogcard-link t--round" href="https://tech.nkhn37.net/python-tech-summary-page/"><div class="c--blogcard-image"><img decoding="async" class="a--blogcard-img-src" width="128" height="72" src="https://tech.nkhn37.net/wp-content/uploads/2024/08/Python-Tech-Pythonプログラミングガイド_new1-640x360.jpg" alt="【Python Tech】プログラミングガイド" /></div><div class="a--blogcard-title d--bold">【Python Tech】プログラミングガイド</div></a></section>

]]></content:encoded>
					
					<wfw:commentRss>https://tech.nkhn37.net/python-class-polymorphism/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Disk: Enhanced  を使用したページ キャッシュ

Served from: tech.nkhn37.net @ 2026-04-23 17:18:29 by W3 Total Cache
-->