Frage Unterschied zwischen __str__ und __repr__?


Was ist der Unterschied zwischen __str__ und __repr__ im Python?


2107
2017-09-17 04:27


Ursprung


Antworten:


Alex gut zusammengefasst, aber überraschenderweise zu knapp.

Lassen Sie mich zunächst die Hauptpunkte in Alex 'Post:

  • Die Standard-Implementierung ist nutzlos (es ist schwer, an eine zu denken, die nicht wäre, aber ja)
  • __repr__ Ziel ist es, eindeutig zu sein
  • __str__ Ziel ist es, lesbar zu sein
  • Behälter __str__ verwendet enthaltene Objekte ' __repr__

Die Standardimplementierung ist nutzlos

Dies ist meistens eine Überraschung, da die Python-Standardeinstellungen ziemlich nützlich sind. In diesem Fall haben Sie jedoch einen Standardwert für __repr__ was wie folgt handeln würde:

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

wäre zu gefährlich gewesen (zB zu leicht in unendliche Rekursion zu kommen, wenn Objekte sich gegenseitig referenzieren). Also Python raus. Beachten Sie, dass es einen Standardwert gibt, der wahr ist: if __repr__ ist definiert, und __str__ ist nicht, das Objekt wird sich so verhalten __str__=__repr__.

Das bedeutet in einfachen Worten: Fast jedes Objekt, das Sie implementieren, sollte funktional sein __repr__ das ist nützlich, um das Objekt zu verstehen. Implementieren __str__ ist optional: Tun Sie das, wenn Sie eine "pretty print" -Funktion benötigen (z. B. von einem Berichtsgenerator verwendet).

Das Ziel von __repr__ ist unmissverständlich

Lass mich gleich rauskommen und es sagen - ich glaube nicht an Debugger. Ich weiß nicht wirklich, wie man irgendeinen Debugger benutzt, und habe nie einen ernsthaft benutzt. Darüber hinaus glaube ich, dass der große Fehler bei Debuggern ihre grundlegende Natur ist - die meisten Fehler, die ich debuggte, passierten vor langer Zeit in einer weit entfernten Galaxie. Das bedeutet, dass ich mit religiösem Eifer beim Holzeinschlag glaube. Protokollierung ist das Lebenselixier eines ordentlichen Feuer-und-Vergessen-Serversystems. Python macht es einfach zu protokollieren: Bei einigen projektspezifischen Wrappern benötigen Sie lediglich a

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)

Aber Sie müssen den letzten Schritt tun - stellen Sie sicher, dass jedes Objekt, das Sie implementieren, einen nützlichen Ausdruck hat, also kann Code wie dieser einfach funktionieren. Deshalb kommt das Eval-Ding auf: wenn du genug Informationen hast eval(repr(c))==cDas heißt, Sie wissen alles, was es zu wissen gibt c. Wenn das leicht genug ist, tun Sie es zumindest auf unscharfe Weise. Wenn nicht, stellen Sie sicher, dass Sie genügend Informationen darüber haben c sowieso. Normalerweise verwende ich ein eval-ähnliches Format: "MyClass(this=%r,that=%r)" % (self.this,self.that). Es bedeutet nicht, dass Sie tatsächlich MyClass konstruieren können, oder dass dies die richtigen Konstruktorargumente sind - aber es ist eine nützliche Form zum Ausdrücken "das ist alles, was Sie über diese Instanz wissen müssen".

Hinweis: Ich habe gebraucht %r oben, nicht %s. Du willst immer benutzen repr() [oder %r Formatierungszeichen, äquivalent] innerhalb __repr__ Implementierung, oder Sie besiegen das Ziel der Rep. Sie möchten unterscheiden können MyClass(3) und MyClass("3").

Das Ziel von __str__ ist lesbar

Konkret soll es nicht eindeutig sein - beachte das str(3)==str("3"). Ebenso, wenn Sie eine IP-Abstraktion implementieren, ist die Darstellung der str wie 192.168.1.1 in Ordnung. Bei der Implementierung einer Datums- / Uhrzeit-Abstraktion kann der String "2010/4/12 15:35:22" usw. sein. Das Ziel ist, ihn so darzustellen, dass ein Benutzer, nicht ein Programmierer, ihn lesen möchte. Unbrauchbare Ziffern abschneiden, vorgeben, eine andere Klasse zu sein - solange es die Lesbarkeit unterstützt, ist es eine Verbesserung.

Behälter __str__ verwendet enthaltene Objekte ' __repr__

Das scheint überraschend, oder? Es ist ein wenig, aber wie lesbar wäre

[moshe is, 3, hello
world, this is a list, oh I don't know, containing just 4 elements]

Sein? Nicht sehr. Insbesondere würden die Zeichenfolgen in einem Container es viel zu einfach finden, ihre Zeichenfolgendarstellung zu stören. Angesichts der Zweideutigkeit, erinnern Sie sich, Python widersteht der Versuchung zu erraten. Wenn Sie das obige Verhalten beim Drucken einer Liste möchten, einfach

print "[" + ", ".join(l) + "]"

(Sie können wahrscheinlich auch herausfinden, was Sie mit Wörterbüchern tun können.

Zusammenfassung

Implementieren __repr__ für jede implementierte Klasse. Dies sollte eine zweite Natur sein. Implementieren __str__ wenn Sie denken, dass es nützlich wäre, eine String-Version zu haben, die auf der Seite der besseren Lesbarkeit zugunsten der Mehrdeutigkeit liegt.


2171
2018-04-13 00:56



Meine Faustregel: __repr__ ist für Entwickler, __str__ ist für Kunden.


369
2017-09-17 11:35



Sofern Sie nicht ausdrücklich etwas anderes tun, haben die meisten Klassen keine hilfreiche Ergebnisse für:

>>> class Sic(object): pass
... 
>>> print str(Sic())
<__main__.Sic object at 0x8b7d0>
>>> print repr(Sic())
<__main__.Sic object at 0x8b7d0>
>>> 

Wie Sie sehen - kein Unterschied und keine Informationen über Klasse und Objekt hinaus id. Wenn Sie nur eines der beiden überschreiben ...:

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

wie Sie sehen, wenn Sie überschreiben __repr__, das wird ALSO auch benutzt __str__aber nicht umgekehrt.

Weitere wichtige Dinge zu wissen: __str__ auf einem integrierten Container verwendet die __repr__, Nicht der __str__, für die Artikel, die es enthält. Und trotz der Worte, die man in typischen Dokumenten findet, stört sich kaum jemand __repr__ von Objekten ist eine Zeichenfolge, die eval kann dazu dienen, ein gleiches Objekt zu erstellen (es ist einfach zu schwer, UND nicht zu wissen, wie das betreffende Modul tatsächlich importiert wurde, macht es tatsächlich unmöglich, es auszugeben).

Also, mein Rat: Konzentriere dich auf das Machen __str__ vernünftig menschlich lesbar, und __repr__ so eindeutig wie du nur kannst, selbst wenn das das unscharfe unerreichbare Ziel des Machens stört __repr__Der zurückgegebene Wert ist als Eingabe für akzeptabel __eval__!


319
2017-09-17 04:49



__repr__: Repräsentation von Python-Objekt normalerweise eval wird es zurück zu diesem Objekt konvertieren

__str__: Was immer du denkst, ist das Objekt in Textform

z.B.

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

143
2017-09-17 04:35



Kurz gesagt, das Ziel von __repr__ ist eindeutig und __str__ ist zu sein   lesbar.

Hier ist ein gutes Beispiel:

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

Lesen Sie diese Dokumentation für den Ausdruck:

repr(object)

Gibt eine Zeichenfolge zurück, die eine druckbare Repräsentation eines Objekts enthält. Dies ist der gleiche Wert, der durch Umrechnungen erhalten wird   Zitate). Es ist manchmal nützlich, auf diese Operation als zugreifen zu können   eine gewöhnliche Funktion. Für viele Typen versucht diese Funktion einen Versuch   um eine Zeichenfolge zurückzugeben, die ein Objekt mit dem gleichen Wert ergibt, wenn   weitergereicht an eval(), ansonsten ist die Darstellung eine Zeichenfolge, eingeschlossen in   spitze Klammern, die den Namen des Objekttyps enthalten   zusammen mit zusätzlichen Informationen oft den Namen und   Adresse des Objekts. Eine Klasse kann steuern, was diese Funktion zurückgibt   für seine Instanzen durch Definieren eines __repr__() Methode.

Hier ist die Dokumentation für str:

str(object='')

Geben Sie eine Zeichenfolge zurück, die eine gut bedruckbare Zeichenfolge enthält   Darstellung eines Objekts. Bei Strings gibt dies die Zeichenfolge zurück   selbst. Der Unterschied mit repr(object)ist das str(object) nicht   Versuchen Sie immer, eine Zeichenfolge zurückzugeben, die akzeptabel ist eval(); es ist   Ziel ist es, eine druckbare Zeichenfolge zurückzugeben. Wenn kein Argument angegeben wird, wird zurückgegeben   die leere Zeichenfolge, ''.


114
2017-10-25 18:38



Was ist der Unterschied zwischen __str__ und __repr__ in Python?

__str__ (gelesen als "dunder (doppelter Unterstrich)") und __repr__ (Lies als "dunder-repper" (für "Repräsentation")) sind beide spezielle Methoden, die Strings basierend auf dem Zustand des Objekts zurückgeben.

__repr__ bietet Backup-Verhalten, wenn __str__ wird vermisst.

Also sollte man zuerst ein schreiben __repr__ Damit können Sie ein äquivalentes Objekt aus der zurückgegebenen Zeichenfolge wiederherstellen, z. verwenden eval oder indem Sie es in einer Python-Shell zeichenweise eingeben.

Zu einem späteren Zeitpunkt kann man einen schreiben __str__ für eine benutzerlesbare String-Repräsentation der Instanz, wenn man es für notwendig hält.

__str__

Wenn Sie ein Objekt drucken oder an es übergeben format, str.format, oder strdann, wenn a __str__ Methode definiert ist, wird diese Methode aufgerufen, andernfalls __repr__ wird verwendet.

__repr__

Das __repr__ Methode wird von der eingebauten Funktion aufgerufen repr und was auf Ihrer Python-Shell ausgegeben wird, wenn ein Ausdruck ausgewertet wird, der ein Objekt zurückgibt.

Da bietet es eine Sicherung für __str__Wenn du nur einen schreiben kannst, fang mit an __repr__

Hier ist die eingebaute Hilfe repr:

repr(...)
    repr(object) -> string

    Return the canonical string representation of the object.
    For most object types, eval(repr(object)) == object.

Das heißt, für die meisten Objekte, wenn Sie eingeben, was von gedruckt wird repr, sollten Sie in der Lage sein, ein äquivalentes Objekt zu erstellen. Dies ist jedoch nicht die Standardimplementierung.

Standardimplementierung von __repr__

Das Standardobjekt __repr__ ist (C Python-Quelle) etwas wie:

def __repr__(self):
    return '<{0}.{1} object at {2}>'.format(
      self.__module__, type(self).__name__, hex(id(self)))

Das bedeutet, dass Sie standardmäßig das Modul, aus dem das Objekt besteht, den Klassennamen und die hexadezimale Darstellung seiner Position im Speicher ausgeben. Beispiel:

<__main__.Foo object at 0x7f80665abdd0>

Diese Information ist nicht sehr nützlich, aber es gibt keine Möglichkeit, abzuleiten, wie man eine kanonische Repräsentation einer bestimmten Instanz genau erstellen könnte, und es ist besser als nichts, und sagt uns zumindest, wie wir es im Gedächtnis eindeutig identifizieren können.

Wie kann __repr__ nützlich sein?

Schauen wir uns an, wie nützlich es sein kann, wenn man die Python-Shell und datetime Objekte. Zuerst müssen wir die importieren datetime Modul:

import datetime

Wenn wir anrufen datetime.now In der Shell sehen wir alles, was wir brauchen, um ein äquivalentes Datetime-Objekt zu erzeugen. Dies wird durch die Datetime erstellt __repr__:

>>> datetime.datetime.now()
datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)

Wenn wir ein Datetime-Objekt drucken, sehen wir ein nettes, vom Menschen lesbares (eigentlich ISO) Format. Dies wird durch datetime implementiert __str__:

>>> print(datetime.datetime.now())
2015-01-24 20:05:44.977951

Es ist einfach, das Objekt, das wir verloren haben, neu zu erstellen, weil wir es nicht einer Variablen zugewiesen haben, indem wir es kopiert und eingefügt haben __repr__ Ausgabe, und dann drucken, und wir bekommen es in der gleichen lesbaren Ausgabe wie das andere Objekt:

>>> the_past = datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)
>>> print(the_past)
2015-01-24 20:05:36.491180

Wie implementiere ich sie?

Während Sie sich entwickeln, sollten Sie in der Lage sein, Objekte möglichst in demselben Zustand zu reproduzieren. So definiert zum Beispiel das Datetime-Objekt __repr__ (Python-Quelle). Es ist ziemlich komplex, wegen all der Attribute, die benötigt werden, um ein solches Objekt zu reproduzieren:

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 = ", ".join(map(str, L))
    s = "%s(%s)" % ('datetime.' + self.__class__.__name__, s)
    if self._tzinfo is not None:
        assert s[-1:] == ")"
        s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
    return s

Wenn Sie möchten, dass Ihr Objekt eine besser lesbare Darstellung hat, können Sie es implementieren __str__ Nächster. Hier ist, wie das Datetime-Objekt (Python-Quelle) implementiert __str__, was es leicht macht, weil es bereits eine Funktion hat, es im ISO-Format anzuzeigen:

def __str__(self):
    "Convert to string, for str()."
    return self.isoformat(sep=' ')

einstellen __repr__ = __str__?

Dies ist eine Kritik einer anderen Antwort hier, die Einstellung vorschlägt __repr__ = __str__.

Rahmen __repr__ = __str__ ist dumm - __repr__ ist ein Fallback für __str__ und ein __repr__, geschrieben für Entwickler im Debugging, sollte geschrieben werden, bevor Sie ein schreiben __str__.

Du brauchst ein __str__ nur wenn Sie eine textuelle Darstellung des Objekts benötigen.

Fazit

Definieren __repr__ Für Objekte, die Sie schreiben, haben Sie und andere Entwickler ein reproduzierbares Beispiel, wenn Sie es bei der Entwicklung verwenden. Definieren __str__ wenn Sie eine lesbare String-Darstellung davon benötigen.


84
2018-01-25 02:01



Abgesehen von allen gegebenen Antworten möchte ich einige Punkte hinzufügen:

1) __repr__() wird aufgerufen, wenn Sie den Namen des Objekts einfach in die interaktive Python-Konsole schreiben und die Eingabetaste drücken.

2) __str__() wird aufgerufen, wenn Sie ein Objekt mit print-Anweisung verwenden.

3) Falls, wenn __str__ fehlt, dann drucken und eine Funktion verwenden str() ruft auf __repr__() des Objekts.

4) __str__() von Containern, wenn sie aufgerufen werden, werden ausgeführt __repr__() Methode seiner enthaltenen Elemente.

5) str() rief nach innen __str__() könnte ohne einen Basisfall und Fehler bei der maximalen Rekursionstiefe rekursiv sein.

6) __repr__() kann anrufen repr() Dadurch wird automatisch versucht, eine unendliche Rekursion zu vermeiden, wobei ein bereits dargestelltes Objekt durch ersetzt wird ....


12
2017-09-08 03:27