ジェネリクスを一言で説明すると?
型に依存しない汎用的なコードを記述するための機能。
ジェネリクスの利点
- 再利用性の向上: ジェネリクスを使うことで、異なる型に対して同じロジックを使える汎用的なコードを作成できる
- 型安全性: ジェネリクスは型を明確にするため、型に関するエラーを型チェッカで検出でき、バグを減らす助けになる
- ドキュメント性の向上: 型ヒントを用いたジェネリクスは、コードの意図を明確にし、他の開発者がコードを理解しやすくなります
基本的なジェネリクスの使い方
ジェネリクスは、TypeVarを用いて実現する。TypeVarは型変数を定義するために使用され、これにより関数やクラスが異なる型に対して汎用的に動作することが可能になる。
例1: ジェネリックな関数
以下は、リスト内の要素を反転するジェネリックな関数の例。この関数は、どの型のリストに対しても同じ動作を行う。
sample1.py
from typing import TypeVar
T = TypeVar('T') # 任意の型Tを定義
def reverse_list(lst: list[T]) -> list[T]:
return lst[::-1]
# 使い方
int_list = [1, 2, 3]
str_list = ["a", "b", "c"]
print(reverse_list(int_list)) # [3, 2, 1]
print(reverse_list(str_list)) # ["c", "b", "a"]
この例では、TypeVar('T')を使って型変数Tを定義した。reverse_list関数はList[T]型を受け取り、同じ型List[T]を返す。これにより、リストの要素がどの型であっても、この関数を適用できる。
例2: ジェネリックなクラス
次に、スタックのようなデータ構造を実装するジェネリックなクラスの例を示す。
sample2.py
from typing import TypeVar, Generic
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()
# 使い方
int_stack: Stack[int] = Stack()
int_stack.push(1)
int_stack.push(2)
print(int_stack.pop()) # 2
str_stack: Stack[str] = Stack()
str_stack.push("a")
str_stack.push("b")
print(str_stack.pop()) # "b"
この例では、Generic[T]を使ってクラスStackがジェネリッククラスであることを宣言している。Stackは任意の型Tに対して動作し、スタック操作を提供する。