Was ist der Unterschied zwischen __str__
und __repr__
in Python?
quelle
Was ist der Unterschied zwischen __str__
und __repr__
in Python?
Alex fasste gut zusammen, war aber überraschenderweise zu prägnant.
Lassen Sie mich zunächst die wichtigsten Punkte in Alex 'Beitrag wiederholen :
__repr__
Ziel ist es, eindeutig zu sein__str__
Ziel ist es, lesbar zu sein__str__
verwendet enthaltene Objekte '__repr__
Die Standardimplementierung ist nutzlos
Dies ist meistens eine Überraschung, da die Standardeinstellungen von Python in der Regel ziemlich nützlich sind. In diesem Fall hätte ein Standardwert __repr__
jedoch Folgendes:
return "%s(%r)" % (self.__class__, self.__dict__)
wäre zu gefährlich gewesen (zum Beispiel zu leicht, um in eine unendliche Rekursion zu geraten, wenn Objekte aufeinander verweisen). Also macht Python Schluss. Beachten Sie, dass es einen Standard gibt, der wahr ist: Wenn __repr__
definiert ist und __str__
nicht, verhält sich das Objekt so, als ob __str__=__repr__
.
Dies bedeutet in einfachen Worten: Fast jedes Objekt, das Sie implementieren, sollte über eine Funktion verfügen __repr__
, die zum Verständnis des Objekts verwendet werden kann. Die Implementierung __str__
ist optional: Tun Sie dies, wenn Sie eine "Pretty Print" -Funktion benötigen (z. B. von einem Berichtsgenerator verwendet).
Das Ziel von __repr__
ist es, eindeutig zu sein
Lassen Sie mich gleich herauskommen und es sagen - ich glaube nicht an Debugger. Ich weiß nicht wirklich, wie man einen Debugger benutzt, und habe noch 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 debugge, sind vor langer, langer Zeit in einer weit entfernten Galaxie aufgetreten. Dies bedeutet, dass ich mit religiösem Eifer an die Protokollierung glaube. Die Protokollierung ist das Lebenselixier eines anständigen Fire-and-Forget-Serversystems. Python erleichtert die Protokollierung: Mit einigen projektspezifischen Wrappern benötigen Sie lediglich eine
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 Repräsentanten hat, damit Code wie dieser einfach funktionieren kann. Aus diesem Grund taucht die „Eval“ -Sache auf: Wenn Sie über genügend Informationen verfügen eval(repr(c))==c
, bedeutet dies , dass Sie alles wissen, was Sie wissen müssen c
. Wenn das einfach genug ist, zumindest auf unscharfe Weise, tun Sie es. Wenn nicht, stellen Sie sicher, dass Sie über genügend Informationen verfügen c
. Normalerweise verwende ich ein eval-ähnliches Format : "MyClass(this=%r,that=%r)" % (self.this,self.that)
. Dies bedeutet nicht, dass Sie MyClass tatsächlich erstellen können oder dass dies die richtigen Konstruktorargumente sind. Es ist jedoch eine nützliche Form, um auszudrücken, dass dies alles ist, was Sie über diese Instanz wissen müssen.
Hinweis: Ich habe %r
oben nicht verwendet %s
. Sie möchten immer repr()
[oder %r
gleichwertiges Formatieren von Zeichen] in der __repr__
Implementierung verwenden, oder Sie vereiteln das Ziel von repr. Sie wollen unterscheiden können MyClass(3)
und MyClass("3")
.
Ziel __str__
ist es, lesbar zu sein
Insbesondere soll es nicht eindeutig sein - beachten Sie das str(3)==str("3")
. Wenn Sie eine IP-Abstraktion implementieren, ist es ebenfalls in Ordnung, wenn die Str wie 192.168.1.1 aussieht. Bei der Implementierung einer Datums- / Zeitabstraktion kann der Str "2010/4/12 15:35:22" usw. sein. Ziel ist es, ihn so darzustellen, dass ein Benutzer, kein Programmierer, ihn lesen möchte. Hacken Sie nutzlose Ziffern ab und geben Sie vor, eine andere Klasse zu sein - solange sie die Lesbarkeit unterstützt, ist dies eine Verbesserung.
Container __str__
verwendet enthaltene Objekte '__repr__
Das scheint überraschend, nicht wahr? Es ist ein wenig, aber wie lesbar wäre es, wenn es ihre verwendet __str__
?
[moshe is, 3, hello
world, this is a list, oh I don't know, containing just 4 elements]
Nicht sehr. Insbesondere die Zeichenfolgen in einem Container würden es viel zu leicht finden, seine Zeichenfolgendarstellung zu stören. Denken Sie daran, dass Python angesichts der Zweideutigkeit der Versuchung widersteht, zu raten. Wenn Sie das obige Verhalten beim Drucken einer Liste wünschen, einfach
print "[" + ", ".join(l) + "]"
(Sie können wahrscheinlich auch herausfinden, was Sie mit Wörterbüchern tun sollen.
Zusammenfassung
Implementieren Sie __repr__
für jede Klasse, die Sie implementieren. Dies sollte eine zweite Natur sein. Implementieren __str__
Sie, wenn Sie der Meinung sind, dass es nützlich wäre, eine String-Version zu haben, die sich auf der Seite der Lesbarkeit irrt.
__repr__
was ich zum Debuggen brauchte. Danke für deine Hilfe.Meine Faustregel:
__repr__
ist für Entwickler,__str__
ist für Kunden.quelle
__str__
sodass normale Entwickler lesbare Objekte haben. Auf der anderen Seite__repr__
ist für die SDK-Entwickler selbst.Sofern Sie nicht ausdrücklich etwas anderes tun, haben die meisten Klassen auch keine hilfreichen Ergebnisse für:
Wie Sie sehen - kein Unterschied und keine Informationen über die Klasse und das Objekt hinaus
id
. Wenn Sie nur einen der beiden überschreiben ...:Wie Sie sehen, wenn Sie überschreiben
__repr__
, wird dies AUCH verwendet__str__
, aber nicht umgekehrt.Weitere wichtige Leckerbissen: Bei
__str__
einem eingebauten Container wird das__repr__
, NICHT das__str__
, für die darin enthaltenen Elemente verwendet. Und trotz der Wörter zu diesem Thema, die in typischen Dokumenten zu finden sind, stört es kaum jemanden, die__repr__
Objekte zu einer Zeichenfolgeeval
zu machen, mit der ein gleiches Objekt erstellt werden kann (es ist einfach zu schwierig, und wenn man nicht weiß, wie das relevante Modul tatsächlich importiert wurde, ist dies tatsächlich der Fall rundum unmöglich).Also, mein Rat: Konzentrieren Sie sich darauf,
__str__
einigermaßen lesbar und__repr__
so eindeutig wie möglich zu machen, auch wenn dies das unscharfe unerreichbare Ziel beeinträchtigt, den__repr__
zurückgegebenen Wert als Eingabe für akzeptabel zu machen__eval__
!quelle
eval(repr(foo))
ein Objekt gleich istfoo
. Sie haben Recht, dass es außerhalb meiner Testfälle nicht funktioniert, da ich nicht weiß, wie das Modul importiert wird, aber dies stellt zumindest sicher, dass es in einem vorhersehbaren Kontext funktioniert . Ich denke, dies ist eine gute Methode, um zu bewerten, ob das Ergebnis von__repr__
explizit genug ist. Wenn Sie dies in einem Komponententest tun, können Sie auch sicherstellen, dass die__repr__
folgenden Änderungen an der Klasse vorgenommen werden.eval(repr(spam)) == spam
(zumindest im richtigen Kontext) odereval(repr(spam))
aSyntaxError
. Auf diese Weise vermeiden Sie Verwirrung. (Und das gilt fast für die eingebauten und die meisten stdlibs, außer zum Beispiel für rekursive Listen, woa=[]; a.append(a); print(eval(repr(a)))
Sie[[Ellipses]]
...) Natürlich mache ich das nicht, um es tatsächlich zu verwendeneval(repr(spam))
, außer als Überprüfung der geistigen Gesundheit in Unit-Tests ... aber ich Kopieren Sie sie manchmal und fügen Sie sierepr(spam)
in eine interaktive Sitzung ein.__str__
für jedes Element anstelle von verwendet werden__repr__
? Scheint mir einfach falsch zu sein, da ich ein lesbares Element__str__
in mein Objekt implementiert habe und wenn es Teil einer Liste ist, sehe ich__repr__
stattdessen das hässlichere .eval(repr(x))
Ichclass A(str, Enum): X = 'x'
bin gerade auf einen nervigen Fehler gestoßen , der damit zusammenhängt, dass selbst bei eingebauten Typen ein Fehler auftritt: SyntaxError wird aktivierteval(repr(A.X))
. Es ist traurig, aber verständlich. Übrigenseval(str(A.X))
funktioniert es tatsächlich, aber natürlich nur, wennclass A
es im Umfang liegt - also ist es wahrscheinlich nicht sehr nützlich.str
Use Elementrepr
weil[1, 2, 3]
! =["1", "2, 3"]
.__repr__
: Die Darstellung eines Python-Objekts wird normalerweise von eval wieder in dieses Objekt konvertiert__str__
: ist, was immer Sie denken, ist dieses Objekt in Textformz.B
quelle
Hier ist ein gutes Beispiel:
Lesen Sie diese Dokumentation für Repr:
Hier ist die Dokumentation für str:
quelle
__str__
(gelesen als "dunder (doppelter Unterstrich) string") und__repr__
(gelesen als "dunder-repper" (für "Darstellung")) sind beide spezielle Methoden, die Strings basierend auf dem Status des Objekts zurückgeben.__repr__
Bietet Sicherungsverhalten, wenn__str__
es fehlt.Man sollte also zuerst eine schreiben
__repr__
, mit der man ein äquivalentes Objekt aus der zurückgegebenen Zeichenfolge wiederherstellen kann, z. B. miteval
oder durch Eingabe von Zeichen für Zeichen in einer Python-Shell.Zu einem späteren Zeitpunkt kann man jederzeit eine
__str__
für den Benutzer lesbare Zeichenfolgendarstellung der Instanz schreiben , wenn man dies für notwendig hält.__str__
Wenn Sie ein Objekt drucken, oder gibt sie an
format
,str.format
oderstr
, dann , wenn eine__str__
Methode definiert ist, wird diese Methode aufgerufen werden, andernfalls__repr__
wird verwendet.__repr__
Die
__repr__
Methode wird von der integrierten Funktion aufgerufenrepr
und wird in Ihrer Python-Shell wiedergegeben, wenn ein Ausdruck ausgewertet wird, der ein Objekt zurückgibt.Da es ein Backup für bietet
__str__
, beginnen Sie mit, wenn Sie nur eines schreiben können__repr__
Hier ist die eingebaute Hilfe zu
repr
:Das heißt, wenn Sie für die meisten Objekte eingeben, von was gedruckt wird
repr
, sollten Sie in der Lage sein, ein gleichwertiges Objekt zu erstellen. Dies ist jedoch nicht die Standardimplementierung.Standardimplementierung von
__repr__
Das Standardobjekt
__repr__
ist ( C Python-Quelle ) wie folgt :Das bedeutet, dass Sie standardmäßig das Modul drucken, von dem das Objekt stammt, den Klassennamen und die hexadezimale Darstellung seiner Position im Speicher - zum Beispiel:
Diese Informationen sind nicht sehr nützlich, aber es gibt keine Möglichkeit abzuleiten, wie man eine kanonische Darstellung einer bestimmten Instanz genau erstellen kann, und sie ist besser als nichts und sagt uns zumindest, wie wir sie im Speicher eindeutig identifizieren können.
Wie kann
__repr__
nützlich sein?Schauen wir uns an, wie nützlich es sein kann, wenn Sie die Python-Shell und
datetime
-Objekte verwenden. Zuerst müssen wir dasdatetime
Modul importieren :Wenn wir
datetime.now
die Shell aufrufen , sehen wir alles, was wir brauchen, um ein äquivalentes datetime-Objekt neu zu erstellen. Dies wird durch die datetime erstellt__repr__
:Wenn wir ein Datum / Uhrzeit-Objekt drucken, sehen wir ein schönes, von Menschen lesbares (tatsächlich ISO) Format. Dies wird durch datetime implementiert
__str__
:Es ist ganz einfach, das verlorene Objekt neu zu erstellen, da wir es keiner Variablen zugewiesen haben, indem wir es aus der
__repr__
Ausgabe kopiert und eingefügt und dann gedruckt haben. Wir erhalten es in derselben vom Menschen lesbaren Ausgabe wie das andere Objekt:Wie implementiere ich sie?
Während der Entwicklung möchten Sie nach Möglichkeit Objekte im gleichen Zustand reproduzieren können. So definiert beispielsweise das datetime-Objekt
__repr__
( Python-Quelle ). Es ist ziemlich komplex, da alle Attribute erforderlich sind, um ein solches Objekt zu reproduzieren:Wenn Ihr Objekt eine besser lesbare Darstellung haben soll, können Sie es als
__str__
Nächstes implementieren . So implementiert das datetime-Objekt ( Python-Quelle )__str__
, was es leicht macht, da es bereits eine Funktion zum Anzeigen im ISO-Format hat:Set
__repr__ = __str__
?Dies ist eine Kritik an einer anderen Antwort, die eine Einstellung vorschlägt
__repr__ = __str__
.Die Einstellung
__repr__ = __str__
ist albern -__repr__
ist ein Fallback für__str__
und eine__repr__
, die für Entwickler beim Debuggen geschrieben wurde, sollte geschrieben werden, bevor Sie eine schreiben__str__
.Sie benötigen eine
__str__
nur, wenn Sie eine Textdarstellung des Objekts benötigen.Fazit
Definieren Sie
__repr__
für Objekte, die Sie schreiben, damit Sie und andere Entwickler ein reproduzierbares Beispiel haben, wenn Sie es während der Entwicklung verwenden. Definieren__str__
Sie, wann Sie eine von Menschen lesbare Zeichenfolgendarstellung benötigen.quelle
type(obj).__qualname__
?Auf Seite 358 des Buches Python Scripting for Computational Science von Hans Petter Langtangen heißt es deutlich
__repr__
Ziele bei einer kompletten String - Darstellung des Objekts;__str__
ist, eine schöne Zeichenfolge zum Drucken zurückzugeben.Also verstehe ich sie lieber als
aus der Sicht des Benutzers, obwohl dies ein Missverständnis ist, das ich beim Erlernen von Python gemacht habe.
Ein kleines, aber gutes Beispiel finden Sie auf derselben Seite wie folgt:
Beispiel
quelle
repr
als Reproduktion zu bezeichnen. Es ist besser, es als repräsentativ zu betrachten.Abgesehen von allen Antworten möchte ich einige Punkte hinzufügen:
1)
__repr__()
wird aufgerufen, wenn Sie einfach den Namen des Objekts in die interaktive Python-Konsole schreiben und die Eingabetaste drücken.2)
__str__()
wird aufgerufen, wenn Sie ein Objekt mit einer print-Anweisung verwenden.3) Im Falle, wenn
__str__
fehlt, wird dann gedruckt und jede Funktionstr()
Invokes__repr__()
des Objekts.4)
__str__()
von Containern führt beim Aufrufen die__repr__()
Methode der enthaltenen Elemente aus.5)
str()
innerhalb aufgerufen__str__()
könnte möglicherweise ohne Basisfall und Fehler bei maximaler Rekursionstiefe wiederkehren.6)
__repr__()
kann aufrufen,repr()
wodurch versucht wird, eine unendliche Rekursion automatisch zu vermeiden, indem ein bereits dargestelltes Objekt durch ersetzt wird...
.quelle
Einfach gesagt:
__str__
wird verwendet, um eine Zeichenfolgendarstellung Ihres Objekts anzuzeigen, die von anderen leicht gelesen werden kann .__repr__
wird verwendet , um eine String - Darstellung zeigen das Objekt.Angenommen, ich möchte eine
Fraction
Klasse erstellen , in der die Zeichenfolgendarstellung eines Bruchs '(1/2)' und das Objekt (Bruchklasse) als 'Bruch (1,2)' dargestellt wird.So können wir eine einfache Bruchklasse erstellen:
quelle
In aller Ehrlichkeit
eval(repr(obj))
wird nie verwendet. Wenn Sie es verwenden, sollten Sie aufhören, da dieseval
gefährlich ist und Zeichenfolgen eine sehr ineffiziente Methode zum Serialisieren Ihrer Objekte darstellen (pickle
stattdessen verwenden).Daher würde ich die Einstellung empfehlen
__repr__ = __str__
. Der Grund dafür ist , dassstr(list)
Anruferepr
auf den Elemente (Ich halte dies für eine der größten Design - Fehler von Python zu sein , die nicht von Python 3 angesprochen wurde). Ein tatsächlicherrepr
wird als Ausgabe von wahrscheinlich nicht sehr hilfreich seinprint [your, objects]
.Um dies zu qualifizieren, besteht meiner Erfahrung nach der nützlichste Anwendungsfall der
repr
Funktion darin, eine Zeichenfolge in eine andere Zeichenfolge einzufügen (mithilfe der Zeichenfolgenformatierung). Auf diese Weise müssen Sie sich keine Sorgen mehr machen, dass Sie Anführungszeichen oder Ähnlichem entkommen. Beachten Sie jedoch, dass hier nichtseval
passiert.quelle
eval(repr(obj))
ist ein Vernunfttest und eine Faustregel. Wenn das ursprüngliche Objekt korrekt neu erstellt wird, haben Sie eine anständige__repr__
Implementierung. Es ist nicht beabsichtigt, dass Sie Objekte tatsächlich auf diese Weise serialisieren.eval
ist nicht von Natur aus gefährlich. Ist das nicht gefährlicher alsunlink
,open
oder um Dateien zu schreiben. Sollten wir aufhören, in Dateien zu schreiben, weil ein böswilliger Angriff möglicherweise einen beliebigen Dateipfad verwenden könnte, um Inhalte darin abzulegen? Alles ist gefährlich, wenn es von dummen Leuten dumm benutzt wird. Idiotie ist gefährlich. Mahn-Krüger-Effekte sind gefährlich.eval
ist nur eine Funktion.Aus einem (inoffiziellen) Python-Referenz-Wiki (Archivkopie) von effbot:
__str__
" Berechnet die" informelle "Zeichenfolgendarstellung eines Objekts. Dies unterscheidet sich__repr__
darin, dass es kein gültiger Python-Ausdruck sein muss: Stattdessen kann eine bequemere oder präzisere Darstellung verwendet werden. "quelle
__repr__
ist keinesfalls erforderlich, um einen gültigen Python-Ausdruck zurückzugeben.str
- Erstellt ein neues String-Objekt aus dem angegebenen Objekt.repr
- Gibt die kanonische Zeichenfolgendarstellung des Objekts zurück.Die Unterschiede:
str ():
repr ():
quelle
Ein Aspekt, der in anderen Antworten fehlt. Es ist wahr, dass im Allgemeinen das Muster ist:
__str__
: lesbar__repr__
: eindeutig, möglicherweise maschinenlesbar übereval
Leider ist diese Unterscheidung fehlerhaft, da Python REPL und auch IPython
__repr__
zum Drucken von Objekten in einer REPL-Konsole verwendet werden (siehe verwandte Fragen zu Python und IPython ). Daher haben Projekte, die auf interaktive Konsolenarbeit ausgerichtet sind (z. B. Numpy oder Pandas), begonnen, die oben genannten Regeln zu ignorieren und__repr__
stattdessen eine für Menschen lesbare Implementierung bereitzustellen .quelle
Aus dem Buch Fluent Python :
quelle
Hervorragende Antworten decken bereits den Unterschied zwischen
__str__
und ab__repr__
, was für mich darauf hinausläuft, dass erstere auch für Endbenutzer lesbar sind und letztere für Entwickler so nützlich wie möglich sind. Angesichts dessen stelle ich fest, dass die Standardimplementierung von__repr__
dieses Ziel häufig nicht erreicht, weil sie weggelassen wird nützliche Informationen für Entwickler.Wenn ich eine einfache habe
__str__
, versuche ich aus diesem Grund im Allgemeinen nur, das Beste aus beiden Welten mit so etwas wie:quelle
Python bevorzugt die Eindeutigkeit gegenüber der Lesbarkeit , den
__str__
Aufruf eines Aufrufstuple
der enthaltenen Objekte__repr__
, die "formale" Darstellung eines Objekts. Obwohl die formale Darstellung schwerer zu lesen ist als eine informelle, ist sie eindeutig und robuster gegen Fehler.quelle
__repr__
wenn es (__str__
) nicht definiert ist! Du liegst also falsch.In einer Nussschale:
quelle
Wenn
print()
aufgerufen wird, wird das Ergebnisdecimal.Decimal(23) / decimal.Decimal("1.05")
der Rohnummer gedruckt; Diese Ausgabe erfolgt in String-Form, die mit erreicht werden kann__str__()
. Wenn wir einfach den Ausdruck eingeben, erhalten wir einedecimal.Decimal
Ausgabe - diese Ausgabe ist in repräsentativer Form, die mit erreicht werden kann__repr__()
. Alle Python-Objekte haben zwei Ausgabeformen. Die Zeichenfolgenform ist für Menschen lesbar. Die Darstellungsform soll eine Ausgabe erzeugen, die, wenn sie einem Python-Interpreter zugeführt wird, (wenn möglich) das dargestellte Objekt reproduziert.quelle
__str__
kann durch Aufrufen für ein Objekt aufgerufen werdenstr(obj)
und sollte eine von Menschen lesbare Zeichenfolge zurückgeben.__repr__
kann durch Aufrufen für ein Objekt aufgerufen werdenrepr(obj)
und sollte ein internes Objekt (Objektfelder / Attribute) zurückgeben.Dieses Beispiel kann helfen:
quelle
Verstehe
__str__
und__repr__
unterscheide sie intuitiv und dauerhaft überhaupt.__str__
Geben Sie den String-getarnten Körper eines bestimmten Objekts zurück, damit er von den Augen gelesen werden kann__repr__
den realen Fleischkörper eines bestimmten Objekts zurück (geben Sie sich selbst zurück), damit er eindeutig identifiziert werden kann.Sehen Sie es in einem Beispiel
Bezüglich
__repr__
Wir können die
__repr__
Ergebnisse bequem arithmetisch bearbeiten.Wenn die Operation auf anwenden
__str__
Gibt nur einen Fehler zurück.
Ein anderes Beispiel.
Ich hoffe, dies hilft Ihnen dabei, konkrete Gründe zu schaffen, um weitere Antworten zu finden.
quelle
__str__
muss ein String-Objekt zurückgeben, während ein__repr__
beliebiger Python-Ausdruck zurückgegeben werden kann.__str__
Implementierung fehlt, wird die__repr__
Funktion als Fallback verwendet. Es gibt keinen Fallback, wenn die__repr__
Funktionsimplementierung fehlt.__repr__
Funktion eine Zeichenfolgendarstellung des Objekts zurückgibt, können wir die Implementierung der__str__
Funktion überspringen .Quelle: https://www.journaldev.com/22460/python-str-repr-functions
quelle
__repr__
wird überall verwendet, außer durchprint
undstr
Methoden (wenn a__str__
definiert ist!)quelle