L07 ch02 — 普通のクラス
テクノロジ系 / L07 class — クラスとデータ構造
L07 ch02 — 普通のクラス
class 文で「データ + 振る舞い」をまとめる基本構文
ゴール
class文でクラスを定義できる__init__で初期化引数を受け取れる- メソッド (self) で振る舞いを足せる
__repr__で表示を整えられる
なぜ「普通のクラス」を学ぶか
@dataclassは「データだけ」を持つクラス向けの糖衣構文- データ + ロジック (振る舞い) を持たせたいときは
classをそのまま書く - FastAPI のサービス層 / ドメイン層では普通のクラスが主役
最小例
class Counter:
def __init__(self, start: int = 0):
self.value = start # 属性 (instance variable)
def increment(self) -> None:
self.value += 1 # 振る舞い (method)
c = Counter()
c.increment()
c.increment()
print(c.value) # 2__init__ と self
class User:
def __init__(self, name: str, age: int):
self.name = name # self.X = X で属性に保存
self.age = age
u = User("Taro", 30)
print(u.name, u.age) # Taro 30__init__は「生成時に1回だけ呼ばれる」初期化メソッドselfは「いま生成中 / 操作中のそのインスタンス」を指す
メソッドを足す
class User:
def __init__(self, name: str, age: int):
self.name = name
self.age = age
def greet(self) -> str:
return f"Hi, I'm {self.name} ({self.age})"
def have_birthday(self) -> None:
self.age += 1
u = User("Taro", 30)
print(u.greet()) # Hi, I'm Taro (30)
u.have_birthday()
print(u.age) # 31__repr__ で「印刷時の見た目」を整える
class User:
def __init__(self, name: str, age: int):
self.name = name
self.age = age
def __repr__(self) -> str:
return f"User(name={self.name!r}, age={self.age})"
u = User("Taro", 30)
print(u) # User(name='Taro', age=30)__repr__ 無しだと <__main__.User object at 0x10a...> でデバッグ困難。
dataclass との使い分け
| 普通のクラス | @dataclass | |
|---|---|---|
__init__ | 自分で書く | 自動生成 |
__repr__ | 自分で書く | 自動生成 |
| 振る舞い (method) | 得意 | 一応書ける |
| 用途 | サービス / ロジック | DTO / 値オブジェクト |
→ 「振る舞いが主」なら普通のクラス、「データが主」なら dataclass
よくある間違い
# ❌ self を忘れる
class Counter:
def __init__(start): # self が無い
value = start # ローカル変数になる
# ❌ 属性とローカル変数の混同
class User:
def __init__(self, name):
name = name # → self.name = name とすべき
# ❌ クラス変数とインスタンス変数の混同
class Cart:
items = [] # ← 全インスタンスで共有される (危険)drill
drill/ — BankAccount クラスを完成させる
拡張課題
- クラス変数 vs インスタンス変数
class Dog:
species = "Canis familiaris" # クラス変数 (全 Dog 共通)
def __init__(self, name):
self.name = name # インスタンス変数 (個別)
@classmethod/@staticmethod
class User:
@classmethod
def from_dict(cls, d: dict) -> "User":
return cls(name=d["name"], age=d["age"])
よくある詰まり
| 症状 | 原因 | 対処 |
|---|---|---|
TypeError: __init__() missing 1 required positional argument: 'self' | メソッドで self を書き忘れ | 第一引数に self を入れる |
インスタンス間で list が共有される | クラス変数として [] を定義 | __init__ 内で self.items = [] |
AttributeError: ... has no attribute | self.X = ... を書き忘れ | __init__ 内で属性を初期化 |
次に学ぶ領域
| 領域 | 続けて読む |
|---|---|
| dataclass (データ専用) | ch01-dataclass |
| 抽象基底クラス / Protocol | ch03 (予定) |
| 継承 | Python 公式チュートリアル §9 |
力試ししたい方は クイズ形式の演習(任意) もあります。読むだけでも十分です。