概要(initは「生まれた直後の初期設定」を行う特別なメソッド)
initは、インスタンス生成時に自動で呼ばれる“コンストラクタ”で、属性の初期化や前提チェックを行います。Pythonではメソッドの第1引数にself(そのインスタンス自身)が渡されるため、init内でself.xxxに値を格納して状態を作ります。
基本の書き方(selfで属性を作り、初期値や前提を入れる)
最小例と動作の流れ
class Person:
def __init__(self, name: str, age: int):
self.name = name # ここで“その人”の属性を作る
self.age = age
def greet(self) -> str:
return f"こんにちは、{self.name}({self.age}歳)です!"
p = Person("太郎", 23) # ここで __init__ が自動で呼ばれる
print(p.greet())
Python- インスタンス作成時にinitが自動実行され、self.nameやself.ageのようなインスタンス属性が設定されます。
selfの意味(必須の第1引数)
selfは「今まさに初期化しているインスタンス」への参照です。呼び出し側はselfを渡しませんが、定義側は必ず第1引数にselfを書きます。
初期化の設計(バリデーション・デフォルト・型ヒント)
前提チェックを入口で弾く
class User:
def __init__(self, user_id: str, name: str | None = None):
if not user_id:
raise ValueError("user_idは必須です")
self.user_id = user_id
self.name = name or "unknown"
Python- 入口で前提が破れていないかを確認し、後段が安心して使える状態にしてから属性を設定します。
デフォルト値とオプション引数
class ApiClient:
def __init__(self, base_url: str, timeout: float = 5.0):
if not base_url.startswith("https://"):
raise ValueError("HTTPSのみ許可")
self.base_url = base_url
self.timeout = timeout
Python- よく使う値はデフォルトにして、必須の値だけ明示的に受け取り、初期化の負担を減らします。
型ヒントで“契約”を明示
引数と属性の型を示すと、エディタ補完や静的チェックが効いて、初期化の誤りが減ります。
継承時の初期化(super().initで親の準備を呼ぶ)
親の初期化を忘れない
class Animal:
def __init__(self, name: str):
self.name = name
class Dog(Animal):
def __init__(self, name: str, breed: str):
super().__init__(name) # 親の初期化を呼ぶ
self.breed = breed
Python- 親が用意する属性や前提があるなら、子クラスのinitでsuper().initを呼んで“親の準備”を済ませます。
上書きと追記の考え方
子クラスでは「親の初期化+子の追加属性」が基本です。親の契約(前提チェックや必須属性)を保ちつつ、必要な拡張だけ足します。
よくあるつまずきと回避(self・戻り値・重い処理)
selfの書き忘れ
- 症状: TypeError(引数数が合わない)。
- 対策: メソッド定義の第1引数は必ずself。Pythonが呼び出し時に自動で渡します。
initは値を“返さない”
- 原則: initの戻り値はNoneでなければならず、returnでオブジェクトを返しません。インスタンスはクラス呼び出し時に作られ、initはその初期化だけを担います。
初期化で重いI/Oをしない
- 症状: 生成だけでネットワークやファイルI/Oが走り、テストと再利用が難しくなる。
- 対策: initは軽く保ち、接続や読込はconnect/loadなど別メソッドに切り出します。
実例で身につける(Web/APIの現実的パターン)
セッションを準備するクライアント
import requests
class ApiClient:
def __init__(self, base_url: str, api_key: str, timeout: float = 5.0):
self.base_url = base_url
self.timeout = timeout
self.session = requests.Session()
self.session.headers.update({"Authorization": f"Bearer {api_key}"})
def get_user(self, uid: str) -> dict:
r = self.session.get(f"{self.base_url}/users/{uid}", timeout=self.timeout)
r.raise_for_status()
return r.json()
Python- initで「再利用するセッションとヘッダー」を作り、各メソッドから使い回すと効率的で安全です。
設定注入→サービス層での整形
class Settings:
def __init__(self, base_url: str, api_key: str):
self.base_url = base_url
self.api_key = api_key
class UserService:
def __init__(self, client: ApiClient):
self.client = client
def profile(self, uid: str) -> dict:
data = self.client.get_user(uid)
return {"id": data.get("id", ""), "name": data.get("name") or "unknown"}
Python- 依存(クライアントや設定)をinitで受け取り、メソッドでドメイン整形に集中します。
補助トピック(dataclass・デフォルトの落とし穴)
dataclassで初期化を自動生成
from dataclasses import dataclass
@dataclass
class UserDTO:
id: str
name: str | None = None
Python- init/repr/比較などを自動生成してくれるため、「属性を持つだけの容器」なら学習初期に便利です。
ミュータブルなデフォルトは避ける
# 悪い例
class Bag:
def __init__(self, items: list = []): # すべてのインスタンスで共有され続ける
self.items = items
# 良い例
class Bag:
def __init__(self, items: list | None = None):
self.items = [] if items is None else items
Python- listやdictをデフォルト引数にすると、全インスタンスで共有されるため予期せぬ蓄積が起きます。Noneを受けて中で新規生成するのが安全です。
まとめ(initは「軽く、正しく、再利用の起点」を作る)
initはインスタンス誕生直後の初期化地点。selfで属性を作り、前提を入口で確認し、デフォルト値で使いやすくする。継承ではsuper().initで親の準備を呼び、重い処理は別メソッドへ切り出す。dataclassで単純な容器は自動化し、ミュータブルなデフォルトは避ける。これを型として徹底すれば、初心者でも「壊れにくく、テストしやすく、拡張しやすい」初期化設計が自然に身につきます。
