__str__ と __repr__:オブジェクトの文字列表現

Python のオブジェクトを print() したとき、何が表示されるかを決めるのが __str____repr__ です。どちらも文字列を返すメソッドですが、目的が違う。

何も定義しないとどうなるか

まずデフォルトの挙動を見てみます。

class User:
    def __init__(self, name, age):
        self.name = name
        self.age = age

user = User("Alice", 30)
print(user)  # <__main__.User object at 0x7f...>

クラス名とメモリアドレスが表示される。これでは何のオブジェクトかわからない。

str:人間向けの表現

__str__print()str() で呼ばれます。人間が読むための、わかりやすい文字列を返します。

class User:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def __str__(self):
        return f"{self.name}{self.age}歳)"

user = User("Alice", 30)
print(user)       # Alice(30歳)
print(str(user))  # Alice(30歳)

ユーザーに見せる文字列を意識して書く。フォーマットは自由。

repr:開発者向けの表現

__repr__ はオブジェクトの「公式な」文字列表現を返します。デバッグやログ出力で使われることを想定しています。

class User:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def __repr__(self):
        return f"User(name={self.name!r}, age={self.age!r})"

user = User("Alice", 30)
print(repr(user))  # User(name='Alice', age=30)

慣習として、__repr__ はそのオブジェクトを再現できるような文字列を返すのが理想。eval(repr(obj)) で同じオブジェクトを作れれば完璧ですが、必須ではありません。

両方定義する

通常は両方定義します。

class User:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def __str__(self):
        return f"{self.name}{self.age}歳)"
    
    def __repr__(self):
        return f"User(name={self.name!r}, age={self.age!r})"

user = User("Alice", 30)
print(user)        # Alice(30歳)
print(repr(user))  # User(name='Alice', age=30)
__str__

人間が読むための表現。print()str() で呼ばれる。わかりやすさ重視。

__repr__

開発者がデバッグするための表現。repr() や対話モードで呼ばれる。正確さ重視。

str がないとき repr が使われる

__str__ を定義せず __repr__ だけ定義した場合、print()__repr__ を使います。

class User:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def __repr__(self):
        return f"User(name={self.name!r}, age={self.age!r})"

user = User("Alice", 30)
print(user)  # User(name='Alice', age=30)(__repr__ が使われる)

逆に __str__ だけ定義して __repr__ を定義しない場合、repr() はデフォルトの <__main__.User object at ...> を返します。

class User:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def __str__(self):
        return f"{self.name}{self.age}歳)"

user = User("Alice", 30)
print(user)        # Alice(30歳)
print(repr(user))  # <__main__.User object at 0x7f...>

だから「どちらか一つだけ定義するなら __repr__ を優先せよ」と言われる。__repr__ があれば __str__ のフォールバックとして機能するからです。

コンテナの中では repr が使われる

リストや辞書の中にオブジェクトを入れて表示すると、__repr__ が呼ばれます。

class User:
    def __init__(self, name):
        self.name = name
    
    def __str__(self):
        return self.name
    
    def __repr__(self):
        return f"User({self.name!r})"

users = [User("Alice"), User("Bob")]
print(users)  # [User('Alice'), User('Bob')](__repr__ が使われる)

for user in users:
    print(user)  # Alice / Bob(__str__ が使われる)

リストの __repr__ が各要素の __repr__ を呼び出している。この挙動を知らないと混乱しがち。

f-string と format での挙動

f-string や format() では __str__ が使われますが、!r を付けると __repr__ を強制できます。

class User:
    def __init__(self, name):
        self.name = name
    
    def __str__(self):
        return self.name
    
    def __repr__(self):
        return f"User({self.name!r})"

user = User("Alice")
print(f"{user}")    # Alice(__str__)
print(f"{user!r}")  # User('Alice')(__repr__)
print(f"{user!s}")  # Alice(__str__ を明示)

ログ出力では !r を使うと、文字列なのか他の型なのかが明確になって便利です。

name = "Alice"
age = 30

# !r なし:型がわからない
print(f"name={name}, age={age}")  # name=Alice, age=30

# !r あり:文字列は引用符付きで表示される
print(f"name={name!r}, age={age!r}")  # name='Alice', age=30

実践的な書き方

よくあるパターンをまとめます。

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __str__(self):
        return f"({self.x}, {self.y})"
    
    def __repr__(self):
        return f"Point(x={self.x}, y={self.y})"

class Person:
    def __init__(self, name, email):
        self.name = name
        self.email = email
    
    def __str__(self):
        return self.name
    
    def __repr__(self):
        return f"Person(name={self.name!r}, email={self.email!r})"

class APIResponse:
    def __init__(self, status, data):
        self.status = status
        self.data = data
    
    def __str__(self):
        return f"Status: {self.status}"
    
    def __repr__(self):
        # data が大きい場合は省略
        data_repr = repr(self.data)
        if len(data_repr) > 50:
            data_repr = data_repr[:50] + "..."
        return f"APIResponse(status={self.status}, data={data_repr})"

まとめ

__repr__ を必ず定義する

デバッグに必須。オブジェクトの状態を正確に表す文字列を返す。__str__ がなければ print() でも使われる。

__str__ は必要なら定義する

ユーザー向けの表示が必要なときに。わかりやすさを重視して、技術的な詳細は省いてよい。

迷ったら __repr__ だけ定義すれば十分。両方定義するなら、__repr__ は正確に、__str__ は簡潔に。