str__と__repr__の違い

python magic-methods repr


Pythonの __str____repr__ の違いは何ですか?




Answer 1 moshez


アレックスはうまくまとめましたが、驚くべきことに、あまりにも簡潔すぎました。

まず、アレックスの投稿の要点を繰り返します。

  • デフォルトの実装は役に立たない(そうでないものを考えるのは難しいが、そうです)
  • __repr__ の目標は、明確にすることです
  • __str__ ゴールは読みやすくすることです
  • コンテナの __str__ の用途は、オブジェクトの含まれる __repr__

デフォルトの実装は役に立たない

Pythonのデフォルトはかなり役立つ傾向があるため、これはほとんど驚きです。ただし、この場合、 __repr__ のデフォルトは次のようになります。

return "%s(%r)" % (self.__class__, self.__dict__)

危険すぎる(たとえば、オブジェクトが相互に参照している場合、無限再帰に入るのは簡単すぎる)。したがって、Pythonは対処します。場合:注意が真である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を構築できること、またはそれらが正しいコンストラクター引数であることを意味するものではありませんが、「これは、このインスタンスについて知っておく必要があるすべてのものです」と表現するのに役立ちます。

注:上記では %s ではなく% %r を使用しました。 __repr__ 実装内で常に repr() [または %r フォーマット文字、同等に] を使用したい場合、または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) + "]"

(おそらく、辞書について何をすべきかを理解することもできます。

Summary

実装するクラスに __repr__ を実装します。これは第二の性質であるべきです。読みやすさの面でエラーになる文字列バージョンがあると便利だと思う場合は __str__ を実装してください。




Answer 2 Ned Batchelder


私の経験則: __repr__ は開発者向け、 __str__ は顧客向けです。




Answer 3 Alex Martelli


あなたが特別に保証するために行動しない限り、ほとんどのクラスでは、どちらのための有益な結果を持っていません。

>>> 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__(object): return 'foo'
... 
>>> print str(Sic())
foo
>>> print repr(Sic())
foo
>>> class Sic(object):
...   def __str__(object): return 'foo'
... 
>>> print str(Sic())
foo
>>> print repr(Sic())
<__main__.Sic object at 0x2617f0>
>>> 

ご覧の __repr__ 、__repr__をオーバーライドすると、__str__にも使用され __str__ 、その逆は行われません。

知っておくべきその他の重要な __str__ :組み込みコンテナの __repr__ 、それが含む項目に __str__ ではなく__repr__を使用します。そして、典型的なドキュメントで見つかった件名の言葉にもかかわらず、オブジェクトの __repr__eval が同等のオブジェクトを構築するために使用できる文字列にすることを誰も気にしません(それはあまりに難しい、そして関連するモジュールが実際にどのようにインポートされたかを知らないことは、それは実際には不可能不可能です)。

だから、私のアドバイス:作りに焦点 __str__ が合理的に人間が読める、と __repr__ あなたはおそらくできる限り明確なように、でも作るのファジー達成不可能な目標を持つこと干渉する場合 __repr__ への入力としての返された値が許容 __eval__




Answer 4 Andrew Clark


__repr__ :Pythonオブジェクトの表現は通常evalで変換されてそのオブジェクトに戻されます

__str__ :テキスト形式のオブジェクトだと思うもの

e.g.

>>> 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



Answer 5 bitoffdev


つまり、 __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(object)

オブジェクトの印刷可能な表現を含む文字列を返します。これは、変換(逆引用符)によって得られる値と同じです。この操作に通常の関数としてアクセスできると便利な場合があります。多くのタイプの場合、この関数は eval() に渡されたときに同じ値のオブジェクトを生成する文字列を返そうとします。それ以外の場合、表現は、オブジェクトのタイプの名前を含む山括弧で囲まれた文字列です。多くの場合、オブジェクトの名前とアドレスを含む追加情報が含まれます。クラスは、 __repr__() メソッドを定義することにより、この関数がインスタンスに対して返すものを制御できます。

以下は str のドキュメントです。

str(object='')

オブジェクトの適切に印刷可能な表現を含む文字列を返します。文字列の場合、これは文字列自体を返します。 repr(object) との違いは、 str(object) が常に eval() に受け入れられる文字列を返そうとするわけではないことです。その目的は、印刷可能な文字列を返すことです。引数が指定されていない場合、空の文字列 '' を返します。