クラスのフィールドにリストを初期値として設定する場合、ミュータブル(変更可能)なオブジェクトの扱いに注意が必要。
間違いやすいパターン
デフォルト引数にリストを直接指定すると、すべてのインスタンスで同じリストオブジェクトが共有されてしまう。
class Task: def __init__(self, name, tags=[]): # 危険なパターン self.name = name self.tags = tags task1 = Task("買い物") task1.tags.append("緊急") task2 = Task("掃除") print(task2.tags) # ['緊急'] ← task1 の変更が影響している
これは Python のデフォルト引数が関数定義時に一度だけ評価されるためである。
正しい方法:None を使う
デフォルト値に None を指定し、__init__ 内で新しいリストを生成する。
class Task: def __init__(self, name, tags=None): self.name = name self.tags = tags if tags is not None else [] task1 = Task("買い物") task1.tags.append("緊急") task2 = Task("掃除") print(task2.tags) # [] ← 正しく独立している
この方法なら、各インスタンスが独自のリストを持つ。
dataclass を使う方法
Python 3.7 以降では dataclass を使うとより簡潔に書ける。field(default_factory=list) を使用する。
from dataclasses import dataclass, field @dataclass class Task: name: str tags: list = field(default_factory=list) task1 = Task("買い物") task1.tags.append("緊急") task2 = Task("掃除") print(task2.tags) # []
default_factory には呼び出し可能オブジェクトを渡す。インスタンス生成のたびにこれが呼ばれ、新しいリストが作られる。
まとめ
従来の __init__ 方式
デフォルト引数に None を指定し、メソッド内で if tags is None のチェックを行う。シンプルなクラスや Python 3.6 以前で使う。
dataclass 方式
field(default_factory=list) を使う。型ヒントと組み合わせてコードが簡潔になり、__init__ や __repr__ が自動生成される。
どちらの方法でも、ミュータブルなデフォルト値を直接指定しないことが重要。