0Pricing
Python Academy · レッスン

TypeVar、ジェネリッククラス、Protocol

再利用可能なジェネリック型と、Protocol による構造的部分型を定義します。

「TypeVar、ジェネリッククラス、Protocol」はCoddyKit上の無料Python Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはPython Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Python Academyコースには全4レッスンが含まれています。

TypeVarとは

TypeVar は型変数を宣言します。これは任意の型を指定できるプレースホルダーで、必要に応じて制約を付けられます。ジェネリック関数やジェネリッククラスで使用します。

from typing import TypeVar

T = TypeVar("T")

def identity(value: T) -> T:
    return value

print(identity(42))      # int
print(identity("hello")) # str

ジェネリック関数

パラメータと戻り値の両方の型に TypeVar を使用する関数では、mypy が引数の型から戻り値の型を推論できます。

from typing import TypeVar

T = TypeVar("T")

def first(items: list[T]) -> T:
    return items[0]

x: int = first([1, 2, 3])     # mypy knows x is int
s: str = first(["a","b","c"]) # mypy knows s is str

制約付きTypeVar

TypeVar に型の制約を渡すと、受け入れ可能な型を制限できます。

from typing import TypeVar

Numeric = TypeVar("Numeric", int, float)

def double(n: Numeric) -> Numeric:
    return n * 2

print(double(5))    # 10
print(double(2.5))  # 5.0
# double("x")  # mypy error

ジェネリッククラス

Generic[T] を継承すると、型変数によってパラメータ化されたクラスを作成できます。

from typing import Generic, TypeVar

T = TypeVar("T")

class Stack(Generic[T]):
    def __init__(self) -> None:
        self._items: list[T] = []

    def push(self, item: T) -> None:
        self._items.append(item)

    def pop(self) -> T:
        return self._items.pop()

stack: Stack[int] = Stack()
stack.push(1)
print(stack.pop())   # 1

複数のTypeVar

複数のTypeVarを使用すると、2つの独立した型によってクラスや関数をパラメータ化できます。

from typing import Generic, TypeVar

K = TypeVar("K")
V = TypeVar("V")

class Pair(Generic[K, V]):
    def __init__(self, key: K, value: V) -> None:
        self.key = key
        self.value = value

p: Pair[str, int] = Pair("age", 30)
print(p.key, p.value)   # age 30

Protocol — 構造的部分型付け

Protocol は、明示的な継承を要求せず、クラスが持つべきメソッドと属性によってインターフェースを定義します(「ダックタイピングを型チェックしたもの」です)。

from typing import Protocol

class Drawable(Protocol):
    def draw(self) -> None: ...

def render(obj: Drawable) -> None:
    obj.draw()

class Circle:
    def draw(self) -> None:
        print("Drawing circle")

render(Circle())   # works — Circle satisfies Drawable

runtime_checkable を使用したProtocol

Protocol に @runtime_checkable を追加すると、実行時に isinstance() チェックを有効にできます。

from typing import Protocol, runtime_checkable

@runtime_checkable
class Closeable(Protocol):
    def close(self) -> None: ...

class File:
    def close(self) -> None: print("closed")

print(isinstance(File(), Closeable))   # True

ProtocolとABCの比較

ABCでは明示的な継承が必要です(class Dog(Animal))。Protocolは構造的な一致によって機能するため、クラスが適切なメソッドを持っていれば、継承関係にかかわらずプロトコルを満たします。

from typing import Protocol
from abc import ABC, abstractmethod

# ABC: nominal typing
class Printable(ABC):
    @abstractmethod
    def display(self) -> None: ...

# Protocol: structural typing
class Displayable(Protocol):
    def display(self) -> None: ...

bound付きTypeVar

TypeVar("T", bound=BaseClass) は、TをBaseClassまたはそのサブクラスに制限します。

from typing import TypeVar

class Animal:
    def speak(self) -> str: return "..."

A = TypeVar("A", bound=Animal)

def make_speak(animal: A) -> str:
    return animal.speak()

ジェネリックエイリアス — Python 3.12

Python 3.12では、型エイリアスを簡潔に定義する type 文と、TypeVarをインポートせずにジェネリックを定義できる class Foo[T] 構文が導入されました。

# Python 3.12+
type Vector = list[float]
type Matrix = list[Vector]

class Stack[T]:
    def __init__(self) -> None: self._items: list[T] = []
    def push(self, item: T) -> None: self._items.append(item)
    def pop(self) -> T: return self._items.pop()

Self型

Self(3.11以降の typing から提供)は、現在のクラスを返すメソッドにアノテーションを付けます。流れるようなインターフェースやサブクラスで役立ちます。

from typing import Self

class Builder:
    def __init__(self) -> None:
        self.parts: list[str] = []

    def add(self, part: str) -> Self:
        self.parts.append(part)
        return self

b = Builder().add("a").add("b")
print(b.parts)   # ["a", "b"]

確認問題

Pythonの型付けにおいて、ProtocolとABCの主な違いは何ですか。

まとめ

TypeVar はジェネリック関数やジェネリッククラスの型プレースホルダーを作成します。Generic[T] はクラスをパラメータ化します。Protocol は継承なしで構造的部分型付けを可能にします。受け入れ可能な型を制限するには、TypeVarに bound= または型制約を使用します。

よくある質問

「TypeVar、ジェネリッククラス、Protocol」レッスンは無料ですか?

はい。「TypeVar、ジェネリッククラス、Protocol」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Python Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Python Academyコースには全4レッスンが含まれています。

「TypeVar、ジェネリッククラス、Protocol」で何を学びますか?

再利用可能なジェネリック型と、Protocol による構造的部分型を定義します。 ブラウザで直接実行するハンズオンコードでPython Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Python Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのPython Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「TypeVar、ジェネリッククラス、Protocol」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このPython Academyレッスンでコードを書いて実行できますか?

はい。すべてのPython Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. 型アノテーションの基礎
  2. 複合型: List、Dict、Optional、Union
  3. TypeVar、ジェネリッククラス、Protocol
  4. mypy の実行と型エラーの修正
← Python Academyに戻る