Pythonの__str__
との違いは何ですか?__repr__
25 に答える
アレックスはうまくまとめましたが、驚くべきことに簡潔すぎました。
まず、アレックスの投稿の要点を繰り返します。
- デフォルトの実装は役に立たない (そうでないものを考えるのは難しいが、そうだ)
__repr__
目標は明確にすることです__str__
目標は読みやすくすることです- コンテナ
__str__
は含まれるオブジェクトを使用します__repr__
デフォルトの実装は役に立たない
Python のデフォルトはかなり便利な傾向があるため、これはほとんど驚きです。ただし、この場合、次の__repr__
ように動作するデフォルトを設定します。
return "%s(%r)" % (self.__class__, self.__dict__)
あまりにも危険でした (たとえば、オブジェクトが相互に参照している場合、無限再帰に陥りやすいなど)。したがって、Python は対処します。true であるデフォルトが 1 つあることに注意してください。__repr__
が定義されていて定義され__str__
ていない場合、オブジェクトはあたかも のように動作します__str__=__repr__
。
つまり、簡単に言えば、実装するほぼすべてのオブジェクトには__repr__
、オブジェクトを理解するために使用できる機能が必要です。実装__str__
はオプションです。「プリティ プリント」機能が必要な場合は実装してください (たとえば、レポート ジェネレータで使用されます)。
の目標は__repr__
明確であることです
率直に言ってみましょう — 私はデバッガーを信じていません。私はデバッガの使い方をよく知りませんし、真剣に使ったこともありません。さらに、デバッガーの大きな欠点は、その基本的な性質にあると私は信じています。私がデバッグするほとんどの障害は、はるか昔、はるか彼方の銀河で発生しています。これは、私が宗教的な熱意を持って伐採を信じていることを意味します。ロギングは、まともなファイア アンド フォーゲット サーバー システムの生命線です。Python を使用すると、ログを簡単に記録できます。おそらくいくつかのプロジェクト固有のラッパーを使用すると、必要なのは
log(INFO, "I am in the weird function and a is", a, "and b is", b, "but I got a null C — using default", default_c)
ただし、最後のステップを実行する必要があります。実装するすべてのオブジェクトに有用な repr があることを確認してください。そうすれば、そのようなコードは問題なく機能します。これが、「eval」が登場する理由です。十分な情報がある場合eval(repr(c))==c
、それは、知っておくべきことをすべて知っていることを意味しますc
。少なくともあいまいな方法でそれが十分に簡単である場合は、それを実行してください。c
そうでない場合は、とにかく十分な情報があることを確認してください。私は通常、eval のような形式を使用します: "MyClass(this=%r,that=%r)" % (self.this,self.that)
. 実際に MyClass を構築できる、またはそれらが正しいコンストラクタ引数であることを意味するわけではありませんが、「これは、このインスタンスについて知る必要があるすべてです」と表現するのに便利な形式です。
注:%r
ではなく、上で使用し%s
ました。repr()
実装内で常に[または%r
フォーマット文字、同等に]使用したい__repr__
、またはreprの目標を破っています。MyClass(3)
とを微分できるようにしますMyClass("3")
。
の目標は__str__
読みやすいことです
具体的には、明確にすることを意図したものではありません — に注意してstr(3)==str("3")
ください。同様に、IP 抽象化を実装する場合、その str を 192.168.1.1 のように見せるだけで十分です。日付/時刻の抽象化を実装する場合、str は "2010/4/12 15:35:22" などになります。目標は、プログラマーではなくユーザーが読みたいと思うような方法で表現することです。役に立たない数字を切り落とし、他のクラスのふりをします — 読みやすさをサポートしている限り、それは改善です。
コンテナ__str__
は含まれるオブジェクトを使用します__repr__
これは驚くべきことですね。少しですが、彼らの__str__
?
[moshe is, 3, hello
world, this is a list, oh I don't know, containing just 4 elements]
あまりない。具体的には、コンテナー内の文字列は、その文字列表現を簡単に乱すことができます。あいまいさに直面しても、Python は推測の誘惑に抵抗することを忘れないでください。リストを印刷するときに上記の動作が必要な場合は、
print("[" + ", ".join(l) + "]")
(おそらく、辞書をどうするかを理解することもできます。
概要
実装__repr__
する任意のクラスに実装します。これは第二の性質であるべきです。__str__
読みやすさの面でエラーになる文字列バージョンがあると便利だと思う場合は実装してください。
私の経験則: __repr__
開発者向けで__str__
あり、顧客向けです。
そうしないように具体的に行動しない限り、ほとんどのクラスは次のいずれにも役立つ結果をもたらしません。
>>> class Sic(object): pass
...
>>> print(str(Sic()))
<__main__.Sic object at 0x8b7d0>
>>> print(repr(Sic()))
<__main__.Sic object at 0x8b7d0>
>>>
ご覧のとおり、違いはなく、クラスとオブジェクトのid
. 2つのうちの1つだけをオーバーライドする場合...:
>>> class Sic(object):
... def __repr__(self): return 'foo'
...
>>> print(str(Sic()))
foo
>>> print(repr(Sic()))
foo
>>> class Sic(object):
... def __str__(self): return 'foo'
...
>>> print(str(Sic()))
foo
>>> print(repr(Sic()))
<__main__.Sic object at 0x2617f0>
>>>
ご覧のとおり、 をオーバーライドすると、それは__repr__
にも使用されますが、__str__
その逆はありません。
知っておくべきその他の重要な情報:__str__
組み込みのコンテナーでは、含まれる__repr__
アイテム__str__
に ではなく を使用します。__repr__
そして、典型的なドキュメントに見られる主題に関する言葉にもかかわらず、 オブジェクトの を、等しいオブジェクトを構築するために使用できる文字列にすることを気にする人はほとんどeval
いません (それは難しすぎます。また、関連するモジュールが実際にどのようにインポートされたかがわからないため、完全に不可能)。
__str__
したがって、私__repr__
のアドバイス:__repr__
の戻り値を__eval__
!
__repr__
: Python オブジェクトの表現は通常、eval によってそのオブジェクトに変換されます。
__str__
: は、テキスト形式のオブジェクトであると思われるものです
例えば
>>> s="""w'o"w"""
>>> repr(s)
'\'w\\\'o"w\''
>>> str(s)
'w\'o"w'
>>> eval(str(s))==s
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
w'o"w
^
SyntaxError: EOL while scanning single-quoted string
>>> eval(repr(s))==s
True
要するに、 の目標は、
__repr__
あいまいさをなくし、__str__
読みやすくすることです。
良い例を次に示します。
>>> import datetime
>>> today = datetime.datetime.now()
>>> str(today)
'2012-03-14 09:21:58.130922'
>>> repr(today)
'datetime.datetime(2012, 3, 14, 9, 21, 58, 130922)'
repr については、次のドキュメントを参照してください。
repr(object)
オブジェクトの印刷可能な表現を含む文字列を返します。これは、変換 (逆引用符) によって得られる値と同じです。この操作に通常の関数としてアクセスできると便利な場合があります。多くの型について、この関数は、 に渡されたときに同じ値を持つオブジェクトを生成する文字列を返そうとします
eval()
。それ以外の場合、オブジェクトの型の名前と追加情報を含む山かっこで囲まれた文字列が表現されます。多くの場合、オブジェクトの名前とアドレスが含まれます。クラスは、メソッドを定義することにより、この関数がそのインスタンスに対して返すものを制御できます__repr__()
。
str のドキュメントは次のとおりです。
str(object='')
オブジェクトのきれいに印刷可能な表現を含む文字列を返します。文字列の場合、これは文字列自体を返します。との違い
repr(object)
はstr(object)
、 が受け入れられる文字列を常に返そうとするとは限らないことeval()
です。その目標は、印刷可能な文字列を返すことです。引数が指定されていない場合は、空の文字列 を返します''
。
Pythonの
__str__
との違いは何ですか?__repr__
__str__
(「dunder (ダブルアンダースコア) 文字列」と__repr__
読む) と (「dunder-repper」 (「表現」の意味) と読む) はどちらも、オブジェクトの状態に基づいて文字列を返す特別なメソッドです。
__repr__
__str__
が欠落している場合のバックアップ動作を提供します。
そのため、最初に a__repr__
を記述して、返される文字列から同等のオブジェクトを再インスタンス化できるようにする必要がありますeval
。
後でいつでも__str__
、ユーザーが読み取り可能なインスタンスの文字列表現を書くことができます。
__str__
オブジェクトを出力するか、 、 、または に渡すformat
場合str.format
、str
メソッド__str__
が定義されている場合はそのメソッドが呼び出され、定義されていない場合はそのメソッドが__repr__
使用されます。
__repr__
__repr__
メソッドは組み込み関数によって呼び出され、repr
オブジェクトを返す式を評価するときに Python シェルにエコーされます。
のバックアップを提供するので、__str__
1つしか書き込めない場合は、最初から__repr__
の組み込みヘルプは次のrepr
とおりです。
repr(...)
repr(object) -> string
Return the canonical string representation of the object.
For most object types, eval(repr(object)) == object.
つまり、ほとんどのオブジェクトでは、 によって出力されるものを入力repr
すると、同等のオブジェクトを作成できるはずです。しかし、これはデフォルトの実装ではありません。
のデフォルト実装__repr__
デフォルトのオブジェクト__repr__
は ( C Python source ) のようなものです:
def __repr__(self):
return '<{0}.{1} object at {2}>'.format(
self.__module__, type(self).__name__, hex(id(self)))
つまり、デフォルトでは、オブジェクトの元のモジュール、クラス名、およびメモリ内の場所の 16 進数表現を出力します。たとえば、次のようになります。
<__main__.Foo object at 0x7f80665abdd0>
この情報はあまり役に立ちませんが、特定のインスタンスの正規表現を正確に作成する方法を導き出す方法はありません。少なくとも、メモリ内で一意に識別する方法を教えてくれるので、何もないよりはましです。
どの__repr__
ように役立ちますか?
datetime
Python シェルとオブジェクトを使用して、それがどれほど役立つかを見てみましょう。まず、datetime
モジュールをインポートする必要があります:
import datetime
シェルで呼び出すdatetime.now
と、同等の datetime オブジェクトを再作成するために必要なものがすべて表示されます。これは datetime によって作成されます__repr__
:
>>> datetime.datetime.now()
datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)
datetime オブジェクトを出力すると、人間が判読できる (実際には ISO) 形式が表示されます。これは、datetime によって実装され__str__
ます。
>>> print(datetime.datetime.now())
2015-01-24 20:05:44.977951
失ったオブジェクトを再作成するのは簡単なことです。これは、出力からコピーして貼り付けてから印刷することによって変数に代入しなかったためです__repr__
。他のオブジェクトと同じ人間が読める出力でそれを取得します。
>>> the_past = datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)
>>> print(the_past)
2015-01-24 20:05:36.491180
どうすれば実装できますか?
開発中は、可能であればオブジェクトを同じ状態で再現できるようにしたいと思うでしょう。たとえば、これは datetime オブジェクトの定義方法です__repr__
( Python source )。このようなオブジェクトを再現するために必要なすべての属性があるため、かなり複雑です。
def __repr__(self):
"""Convert to formal string, for repr()."""
L = [self._year, self._month, self._day, # These are never zero
self._hour, self._minute, self._second, self._microsecond]
if L[-1] == 0:
del L[-1]
if L[-1] == 0:
del L[-1]
s = "%s.%s(%s)" % (self.__class__.__module__,
self.__class__.__qualname__,
", ".join(map(str, L)))
if self._tzinfo is not None:
assert s[-1:] == ")"
s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
if self._fold:
assert s[-1:] == ")"
s = s[:-1] + ", fold=1)"
return s
オブジェクトをより人間が読める表現にしたい場合は、次に実装できます__str__
。datetime オブジェクト ( Python ソース) が を実装する方法は次の__str__
とおりです。これは、ISO 形式で表示する関数が既にあるため、簡単に実行できます。
def __str__(self):
"Convert to string, for str()."
return self.isoformat(sep=' ')
セット__repr__ = __str__
?
これは、設定を提案する別の回答に対する批判です__repr__ = __str__
。
設定__repr__ = __str__
はばかげています -__repr__
は と のフォールバックで__str__
あり、__repr__
開発者がデバッグで使用するために書かれており、__str__
.
__str__
オブジェクトのテキスト表現が必要な場合にのみ が必要です。
結論
作成するオブジェクトを定義__repr__
して、開発時にそれを使用するときに、あなたや他の開発者が再現可能な例を持てるようにします。__str__
人間が読める文字列表現が必要な場合を定義します。
ハンス・ペッター・ラングタンゲンによる計算科学のための Python スクリプトの本の 358 ページには、次のように明確に述べられています。
- は、オブジェクトの
__repr__
完全な文字列表現を目指しています。 - は
__str__
、印刷用の適切な文字列を返すことです。
だから、私はそれらを次のように理解することを好みます
- repr = 再現する
- str = 文字列 (表現)
これは、Python を学習するときに私が犯した誤解ですが、ユーザーの観点からです。
小さくても良い例も同じページに次のように示されています。
例
In [38]: str('s')
Out[38]: 's'
In [39]: repr('s')
Out[39]: "'s'"
In [40]: eval(str('s'))
Traceback (most recent call last):
File "<ipython-input-40-abd46c0c43e7>", line 1, in <module>
eval(str('s'))
File "<string>", line 1, in <module>
NameError: name 's' is not defined
In [41]: eval(repr('s'))
Out[41]: 's'
与えられたすべての回答とは別に、いくつかの点を追加したいと思います:-
1)__repr__()
は、インタラクティブな python コンソールにオブジェクトの名前を入力して Enter キーを押すだけで呼び出されます。
2)__str__()
オブジェクトを print ステートメントで使用すると呼び出されます。
3) が欠落している場合は、オブジェクトの呼び出しを__str__
使用して印刷および関数を実行します。str()
__repr__()
4)__str__()
コンテナーの場合、呼び出されると__repr__()
、含まれている要素のメソッドが実行されます。
5)str()
内部で呼び出されると__str__()
、基本ケースなしで再帰する可能性があり、再帰の最大深度でエラーが発生する可能性があります。
6)自動的に無限再帰を回避しようとする which を__repr__()
呼び出すことができrepr()
、既に表現されているオブジェクトを に置き換えます...
。
正直なところ、eval(repr(obj))
使用されることはありません。eval
それを使用していることに気付いた場合は、危険であり、文字列はオブジェクトをシリアル化する非常に非効率的な方法であるため、停止する必要があります(pickle
代わりに使用してください)。
したがって、を設定することをお勧めします__repr__ = __str__
。その理由は、要素をstr(list)
要求repr
することです(これは、Python 3では対処されなかったPythonの最大の設計上の欠陥の1つであると私は考えています)。実際のrepr
は、の出力としてはおそらくあまり役に立ちませんprint([your, objects])
。
これを修飾するために、私の経験では、関数の最も有用なユースケースはrepr
、文字列を別の文字列内に配置することです(文字列フォーマットを使用)。このように、引用符などをエスケープすることを心配する必要はありません。ただし、eval
ここでは何も起こらないことに注意してください。
effbotによる(非公式の)PythonリファレンスWiki(アーカイブコピー)から:
__str__
"オブジェクトの「非形式的な」文字列表現を計算します。これは、有効な Python 式である必要がないという点で とは異なります。__repr__
代わりに、より便利で簡潔な表現を使用できます。 "
str
- 指定されたオブジェクトから新しい文字列オブジェクトを作成します。
repr
- オブジェクトの正規の文字列表現を返します。
違い:
str():
- オブジェクトを読み取り可能にする
- エンドユーザー向けの出力を生成します
repr():
- オブジェクトを再現するコードが必要
- 開発者向けの出力を生成します
__str__
優れた回答は、との違いをすでにカバーしてい__repr__
ます。私にとっては、前者はエンド ユーザーでも読みやすく、後者は開発者にとって可能な限り有用であるということです。それを考えると、開発者にとって有用な情報が省略され__repr__
ているため、デフォルトの実装ではこの目標を達成できないことがよくあります。
このため、私が十分に単純な を持っている場合__str__
、私は通常、次のようなもので両方の世界を最大限に活用しようとします:
def __repr__(self):
return '{0} ({1})'.format(object.__repr__(self), str(self))
>>> print(decimal.Decimal(23) / decimal.Decimal("1.05"))
21.90476190476190476190476190
>>> decimal.Decimal(23) / decimal.Decimal("1.05")
Decimal('21.90476190476190476190476190')
生の数値の結果に対してがprint()
呼び出されると、出力されます。decimal.Decimal(23) / decimal.Decimal("1.05")
この出力は、で実現できる文字列形式__str__()
です。単純に式を入力すると、decimal.Decimal
出力が得られます — この出力は、で実現できる表現形式__repr__()
です。すべての Python オブジェクトには 2 つの出力形式があります。文字列形式は、人間が判読できるように設計されています。表現形式は、Python インタープリターに供給された場合に (可能な場合) 表現されたオブジェクトを再現する出力を生成するように設計されています。
__repr__
print
andメソッド以外のあらゆる場所で使用されstr
ます ( a__str__
が定義されている場合!)