概要(reprは「開発者向けの公式な文字列表現」)
reprは、オブジェクトの“正確で曖昧さのない”文字列表現を返す特別メソッドです。REPLやデバッグ、ログでの診断に使われ、可能ならその文字列からオブジェクトを再構築できる形(再現可能性)を目指します。対になるstrが“人向けの読みやすい表示”なのに対し、reprは“開発者向けの確実な表示”です。
基本の使い方(print/repr/REPLでの挙動を理解する)
最小例とREPLでの表示
class Person:
def __init__(self, name: str, age: int):
self.name = name
self.age = age
def __repr__(self) -> str:
return f"Person(name={self.name!r}, age={self.age!r})"
p = Person("太郎", 23)
print(repr(p)) # Person(name='太郎', age=23)
p # REPLでは __repr__ が表示に使われる
PythonREPL(対話環境)やloggingの詳細出力ではreprが使われます。主要属性を含め、型名がわかる形式で返すのが基本です。
strとの違い(役割の線引き)
class Price:
def __init__(self, amount: float, currency: str = "JPY"):
self.amount = amount
self.currency = currency
def __str__(self) -> str:
return f"{self.amount:.2f} {self.currency}" # 人向けの簡潔表示
def __repr__(self) -> str:
return f"Price(amount={self.amount!r}, currency={self.currency!r})" # 開発者向け
PythonUIやユーザ向けにはstr、デバッグやREPLにはrepr。両方を用途に合わせて実装すると、表示で迷わなくなります。
設計のポイント(再現可能性・曖昧さ排除・安全性)
再現可能性を意識する
「可能なら」repr文字列を評価すれば同等のオブジェクトを作れる形を目指します。最低限、クラス名と主要属性を明示し、文字列は!rでクォートを含めて曖昧さを排除します。
class Rect:
def __init__(self, w: float, h: float):
self.w = w; self.h = h
def __repr__(self) -> str:
return f"Rect(w={self.w!r}, h={self.h!r})"
Python機微情報は出さない(安全なrepr)
APIキーやトークンなどをそのままreprに出すのは危険です。必要なら要約・マスクで表現し、完全な値は表示しない方針を守ります。
class ApiKey:
def __init__(self, token: str):
self.token = token
def __repr__(self) -> str:
t = self.token
masked = (t[:4] + "..." + t[-4:]) if len(t) > 8 else "***"
return f"ApiKey(token={masked!r})"
Python長さと安定性を保つ
大量要素のコレクションを丸ごとreprに入れると読みにくくなります。件数や一部要約、上限表示で“読めるサイズ”に保つのが実践的です。
実務での使い方(モデル・クライアント・例外の診断性向上)
モデルのreprで状態を一目で把握する
class UserModel:
def __init__(self, uid: str, name: str | None = None, role: str = "user"):
self.uid = uid
self.name = name or "unknown"
self.role = role
def __repr__(self) -> str:
return f"UserModel(uid={self.uid!r}, name={self.name!r}, role={self.role!r})"
Pythonログに出した瞬間、何が入っているかが明確になります。
クライアントの接続概要をreprで短く明確に
import requests
class ApiClient:
def __init__(self, base_url: str, timeout: float = 5.0):
self.base_url = base_url
self.timeout = timeout
self.session = requests.Session()
def __repr__(self) -> str:
return f"ApiClient(base_url={self.base_url!r}, timeout={self.timeout!r})"
Python動作に重要な設定だけを明示し、セキュア情報は含めないのが鉄則です。
例外型のreprで原因追跡を助ける
class ServiceError(Exception):
def __init__(self, message: str, uid: str | None = None):
super().__init__(message)
self.uid = uid
def __repr__(self) -> str:
return f"ServiceError(message={self.args[0]!r}, uid={self.uid!r})"
Pythonログで例外が並んでも、どのケースか即判別できます。
深掘りトピック(コンテナのrepr・dataclass・フォールバック)
コンテナ内での表示
listやdictにオブジェクトが入ると、それらのreprが使われます。つまりクラスにreprが無いと、リスト表示が読みにくくなります。代表クラスにはreprを必ず用意しましょう。
dataclassのrepr自動生成
単純なデータ容器ならdataclassを使えば、フィールドを含むreprが自動生成されます。独自の表示にしたい場合はreprを上書きします。
from dataclasses import dataclass
@dataclass
class Point:
x: float
y: float
# repr: Point(x=1.0, y=2.0)
Pythonstrへのフォールバック
reprが未実装でも、str()が用意されていればそちらが表示に使われる場面があります。ただしREPLは通常reprを使うため、デバッグ重視ならreprを先に整えるのが近道です。
例題(注文・ユーザー・クライアントのreprでデバッグ効率を上げる)
一貫したreprを揃える
class Order:
def __init__(self, order_id: str, items: list[tuple[str, int]]):
self.order_id = order_id
self.items = items
self.status = "init"
def __repr__(self) -> str:
return f"Order(order_id={self.order_id!r}, status={self.status!r}, items={len(self.items)!r})"
class User:
def __init__(self, uid: str, name: str | None = None):
self.uid = uid
self.name = name or "unknown"
def __repr__(self) -> str:
return f"User(uid={self.uid!r}, name={self.name!r})"
import requests
class Client:
def __init__(self, base_url: str, key: str, timeout: float = 5.0):
self.base_url = base_url
self.key = key
self.timeout = timeout
self.session = requests.Session()
def __repr__(self) -> str:
return f"Client(base_url={self.base_url!r}, timeout={self.timeout!r})"
Pythonログに並べても判読しやすく、重要情報だけが揃うため、原因究明が速くなります。
まとめ(reprは「開発者のための真面目な顔」)
reprは、型名・主要属性・曖昧さ排除(!r)を備えた、開発者向けの公式表示です。可能なら再現可能性を意識し、機微情報は出さない。大量データは要約し、REPLやログでの見通しを最優先にする。strと役割を分け、代表的なクラスには必ずreprを用意する。これだけで、デバッグの速さと品質が一段上がります。
