Pythonの__repr__メソッドを理解する
これはなに
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__
メソッドの実装例である。
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__
は下記のように実装する。
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__
は一般的な使用のためのより読みやすい情報を提供するのが望ましい。
Discussion