Pythonのデータクラス(dataclass)完全入門!通常クラスとの違いからfrozen・__post_init__まで徹底解説
「Pythonでクラスを作るたびに__init__を何度も書くのが面倒くさい…」
そう感じたことはありませんか?実はPython 3.7から、そんな悩みをスッキリ解決してくれるデータクラス(dataclass)という機能が標準搭載されています。
今回は、dataclassの基本的な使い方から、通常クラスとの違い、frozenや__post_init__などの応用機能まで、一気に解説していきます!Python中級を目指しているあなたにとって、かなり実践的な内容になっていますよ😊
対象読者と前提知識

- ✅ Pythonのクラス・インスタンスの基礎は知っている
- ✅
__init__メソッドを書いたことがある - ✅ Python中級レベルへのステップアップを目指している
「クラスって何?」という方は、まずインスタンスとクラスの基礎を押さえてから読んでみてください。
データクラス(dataclass)って何?
dataclassを一言で表すなら、「主にデータを保持するためのクラスを、簡潔に書ける仕組み」です。
イメージとしては、「設計書のテンプレートが自動で埋まる」感じです。通常は自分で書かなければいけない__init__・__repr__・__eq__などのメソッドを、Pythonが自動で生成してくれます。
使い方はシンプルで、@dataclassデコレータをクラスに付けるだけ。まずは通常クラスとの書き比べを見てみましょう。
通常クラスとdataclassの違いを比べてみよう
下記は「商品」を表すクラスを、通常クラスとdataclassの両方で書いた例です。
通常クラスで書いた場合
# 通常クラス
class Product:
def __init__(self, name: str, price: int, stock: int):
self.name = name
self.price = price
self.stock = stock
def __repr__(self):
return f"Product(name={self.name!r}, price={self.price!r}, stock={self.stock!r})"
def __eq__(self, other):
if not isinstance(other, Product):
return NotImplemented
return (self.name, self.price, self.stock) == (other.name, other.price, other.stock)
p = Product("リンゴ", 150, 100)
print(p) # Product(name='リンゴ', price=150, stock=100)
dataclassで書いた場合
from dataclasses import dataclass
# dataclassで書くとこんなにスッキリ!
@dataclass
class Product:
name: str
price: int
stock: int
p = Product("リンゴ", 150, 100)
print(p) # Product(name='リンゴ', price=150, stock=100)
ポイントをまとめるとこんな感じです👇
- ✅
__init__を自分で書かなくてOK - ✅
__repr__(print時の表示)が自動生成される - ✅
__eq__(等値比較)が自動生成される - ✅ 型アノテーションでフィールドを定義する
同じことをするのに、行数が圧倒的に少なくなりますよね。これがdataclassの最大の魅力です😊
デフォルト値と field() の使い方
dataclassでは、フィールドにデフォルト値を設定することもできます。
from dataclasses import dataclass, field
@dataclass
class Product:
name: str
price: int
stock: int = 0 # デフォルト値をシンプルに設定
tags: list = field(default_factory=list) # リストのデフォルトはfieldを使う!
# stockを省略して作成
p1 = Product("バナナ", 80)
print(p1) # Product(name='バナナ', price=80, stock=0, tags=[])
# tagsを指定して作成
p2 = Product("オレンジ", 120, 50, ["フルーツ", "柑橘"])
print(p2) # Product(name='オレンジ', price=120, stock=50, tags=['フルーツ', '柑橘'])
ここが重要です❗
- リスト・辞書などのミュータブルなオブジェクトをデフォルト値にしたい場合は、
field(default_factory=...)を使う必要があります - 直接
tags: list = []と書くとエラーになります(Pythonがわざと弾いてくれる) - これは通常クラスでも「全インスタンスがリストを共有してしまうバグ」が起きやすいため、dataclassが安全に守ってくれている仕組みです
frozen=True で不変なクラスを作る
@dataclass(frozen=True)と指定すると、インスタンス生成後に値を書き換えられないイミュータブルなクラスを作れます。
イメージとしては、「読み取り専用の設定ファイル」です。一度作ったら誰にも変更させたくないデータを表すのに便利です。
from dataclasses import dataclass
@dataclass(frozen=True)
class Config:
host: str
port: int
debug: bool = False
cfg = Config("localhost", 8080)
print(cfg) # Config(host='localhost', port=8080, debug=False)
# 値を書き換えようとするとエラーになる
try:
cfg.port = 9090
except Exception as e:
print(f"エラー: {e}")
# エラー: cannot assign to field 'port'
# frozenなのでハッシュ化できる(辞書のキーやsetの要素にも使える!)
config_set = {cfg}
print(config_set) # {Config(host='localhost', port=8080, debug=False)}
frozen=Trueにするとうれしいことがあります👇
- ✅ 意図しない値の書き換えを防げる
- ✅
__hash__が自動生成されるので、辞書のキーやセットの要素として使える - ✅ マルチスレッド環境でも安全に使いやすくなる
__post_init__ で初期化後に処理を追加する
「dataclassで自動生成された__init__に、追加の処理を入れたい」というケースも出てきます。そんな時に使うのが__post_init__です。
__post_init__は、__init__が実行されたあとに自動的に呼び出される特別なメソッドです。
from dataclasses import dataclass
@dataclass
class Product:
name: str
price: int
stock: int = 0
def __post_init__(self):
# 初期化後のバリデーション処理
if self.price < 0:
raise ValueError(f"価格は0以上でなければなりません。受け取った値: {self.price}")
if self.stock < 0:
raise ValueError(f"在庫数は0以上でなければなりません。受け取った値: {self.stock}")
# 名前の前後の空白を自動トリム
self.name = self.name.strip()
# 正常なインスタンス
p1 = Product(" メロン ", 500, 10)
print(p1) # Product(name='メロン', price=500, stock=10) ← 空白が消えている!
# バリデーションエラーの確認
try:
p2 = Product("スイカ", -100)
except ValueError as e:
print(f"エラー: {e}")
# エラー: 価格は0以上でなければなりません。受け取った値: -100
__post_init__が活躍するシーンはこんな感じです👇
- ✅ 入力値のバリデーション(不正な値を弾く)
- ✅ 入力値の自動変換・正規化
- ✅ 他のフィールドをもとに計算した値のセット
dataclassの主なオプション一覧
最後に、@dataclassデコレータで指定できる主なオプションを整理しておきます。
| オプション | デフォルト | 説明 |
|---|---|---|
init |
True | __init__を自動生成するか |
repr |
True | __repr__を自動生成するか |
eq |
True | __eq__を自動生成するか |
order |
False | 比較演算子(<, >など)を自動生成するか |
frozen |
False | イミュータブル(書き換え不可)にするか |
slots |
False | __slots__を使ってメモリ効率を上げるか(Python 3.10+) |
まとめ
今回はPythonのデータクラス(dataclass)について、通常クラスとの違いから応用機能まで解説しました。
- ✅
@dataclassデコレータで__init__・__repr__・__eq__が自動生成される - ✅ リストなどのデフォルト値には
field(default_factory=...)を使う - ✅
frozen=Trueでイミュータブルなクラスが作れる - ✅
__post_init__でバリデーションや追加処理を書ける
dataclassは「データを持ち運ぶためのクラス」をシンプルかつ安全に書けるとても便利な機能です。APIのレスポンスデータや設定情報の管理など、実際のプロジェクトでも大活躍しますよ😊
「むずかしそう」と思っていたdataclassも、ここまで読めば「使えそう!」に変わったんじゃないでしょうか。ぜひ自分のコードで試してみてください!
こちらも読まれています
📚 関連商品・おすすめ書籍
※本記事にはアフィリエイトリンクが含まれます。





