📚

Pythonの__repr__メソッドを理解する

2023/09/19に公開

これはなに

Pythonのオブジェクトが持つ特殊メソッド__repr__について調べたメモ。

特殊メソッド__repr__とは

__repr__は、objectクラスで定義されている、オブジェクトの「公式な(official)」文字列表現を返すための特殊メソッドである。

__repr__objectクラスで定義されており、すべてのクラスは暗黙的にobjectクラスを継承する。そのため、すべてのクラスに__repr__メソッドは定義(継承)されている

__repr__の目的

このメソッドの目的は、そのオブジェクトの「公式な(official)」文字列表現を返し、オブジェクトを再作成するのに役立つ情報を文字列で提供することである。

「公式な文字列表現」とは、下記の特性を指す。

  • 一貫性: 同じオブジェクトに対しては、常に同じ文字列表現を返すべきである
  • 明確性: 返される文字列表現は、そのオブジェクトのタイプや内容を明確に示すべきである
  • 再現性: 理想的には、文字列表現をeval()関数に渡すことで、同じ属性や状態を持つ新しいオブジェクトが生成されるようにするべきである

主にデバッグ時の利用を想定している。

__repr__の実装

__repr__戻り値は文字列でなければならない。かつ、この文字列は、適切な環境が与えられた場合に、「同じ値を持つオブジェクトを再作成するために使用できる有効なPython式」のように見えるべきである。つまり、理想的には、eval(repr(obj))がオリジナルのobjと同等のオブジェクトを生成すべきである。

もしこれが不可能な場合は、<...some useful description...> のような形式で、役立つ説明を文字列として返さなければならない。たとえば、objectクラスの__repr__の実装は、<classname object at memory_location>のような形式で返される。このデフォルトの挙動を変更する場合は、__repr__をオーバーライドして独自の表現を提供する。

実装例

下記は、__repr__メソッドの実装例である。

__repr__の実装例
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

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

このクラスを利用してオブジェクトを生成すると、以下のように動作する。

p = Point(3, 4)
print(repr(p))  # Point(3, 4)

このように、もとのオブジェクトpを再生成するためのPython式(ここではPoint(3, 4))を返すように、__repr__は実装すべきである。

__repr__の使い方

__repr__メソッドは、下記の場合に自動で呼び出される。

  • オブジェクトを組み込み関数repr()に渡すとき
  • オブジェクトをインタラクティブシェルで表示するとき
  • __str__メソッドがオブジェクトで実装されていない場合に、print()などでオブジェクトを文字列として表示するとき

__repr____str__の違い

__repr__メソッドと似たメソッドに__str__メソッドがある。どちらもオブジェクトに関する文字列を返す。しかし、両者には明確な目的の違いがある。

__repr__メソッドはオブジェクトの「公式な」文字列表現の提供を目的としている。言いかえれば、そのオブジェクトと同等なオブジェクトを再作成するための、Python式の提供が目的である。ゆえに、戻り値に読みやすさやわかりやすさは求められない。求められるのは、その戻り値を組み込み関数eval()に渡した際に、もとのオブジェクトと同等のオブジェクトを生成できるPython式(を表す文字列)である。

一方で、__str__メソッドは、オブジェクトの「非公式な(informal)」文字列表現の提供を目的としている。言いかえれば、より人間に読みやすい文字列表現を提供することを目的としている。そのため、このメソッドの戻り値には、そのオブジェクトに関する情報を読みやすくわかりやすい形で表現した文字列が求められる。

具体例

たとえば、__repr____str__は下記のように実装する。

__repr__と__str__の違い
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

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

    def __str__(self):
        return f"{self.name}, {self.age} years old"

このクラスを使用すると、以下のような結果が得られる。

p = Person("Alice", 30)

print(repr(p))  # Person(name='Alice', age=30)
print(str(p))  # Alice, 30 years old
print(p)  # Alice, 30 years old (これは`__str__`の結果だが、`__str__`が未定義の場合は`__repr__`が表示される)

このように、__repr__はオブジェクトを再構築するのに役立つ情報を提供し、__str__は一般的な使用のためのより読みやすい情報を提供するのが望ましい。

参考文献・URL

Discussion