Antworten:
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.
__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:
>>> 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 die Klasse und das Objekt hinaus id
. Wenn Sie nur einen 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__
, 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 Zeichenfolge eval
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__
!
eval(repr(foo))
ein Objekt gleich ist foo
. 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) oder eval(repr(spam))
a SyntaxError
. 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, wo a=[]; a.append(a); print(eval(repr(a)))
Sie [[Ellipses]]
...) Natürlich mache ich das nicht, um es tatsächlich zu verwenden eval(repr(spam))
, außer als Überprüfung der geistigen Gesundheit in Unit-Tests ... aber ich Kopieren Sie sie manchmal und fügen Sie sie repr(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))
Ich class 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 aktiviert eval(repr(A.X))
. Es ist traurig, aber verständlich. Übrigens eval(str(A.X))
funktioniert es tatsächlich, aber natürlich nur, wenn class A
es im Umfang liegt - also ist es wahrscheinlich nicht sehr nützlich.
str
Use Element repr
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 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
Kurz gesagt, das Ziel von
__repr__
ist es, eindeutig und__str__
lesbar zu sein.
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 Repr:
repr(object)
Gibt eine Zeichenfolge zurück, die eine druckbare Darstellung eines Objekts enthält. Dies ist der gleiche Wert, der durch Conversions (umgekehrte Anführungszeichen) erzielt wird. Es ist manchmal nützlich, als normale Funktion auf diesen Vorgang zugreifen zu können. Bei vielen Typen versucht diese Funktion, eine Zeichenfolge zurückzugeben, die bei Übergabe ein Objekt mit demselben Wert ergibt
eval()
. Andernfalls ist die Darstellung eine Zeichenfolge in spitzen Klammern, die den Namen des Objekttyps zusammen mit zusätzlichen Informationen enthält oft einschließlich des Namens und der Adresse des Objekts. Eine Klasse kann steuern, was diese Funktion für ihre Instanzen zurückgibt, indem sie eine__repr__()
Methode definiert.
Hier ist die Dokumentation für str:
str(object='')
Gibt eine Zeichenfolge zurück, die eine gut druckbare Darstellung eines Objekts enthält. Bei Zeichenfolgen wird die Zeichenfolge selbst zurückgegeben. Der Unterschied
repr(object)
besteht darin, dassstr(object)
nicht immer versucht wird, eine Zeichenfolge zurückzugeben, die für akzeptabel isteval()
. Ziel ist es, eine druckbare Zeichenfolge zurückzugeben. Wenn kein Argument angegeben wird, wird die leere Zeichenfolge zurückgegeben''
.
Was ist der Unterschied zwischen
__str__
und__repr__
in Python?
__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. mit eval
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
oder str
, 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 aufgerufen repr
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
:
repr(...)
repr(object) -> string
Return the canonical string representation of the object.
For most object types, eval(repr(object)) == object.
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.
__repr__
Das Standardobjekt __repr__
ist ( C Python-Quelle ) wie folgt :
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 drucken, von dem das Objekt stammt, den Klassennamen und die hexadezimale Darstellung seiner Position im Speicher - zum Beispiel:
<__main__.Foo object at 0x7f80665abdd0>
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.
__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 das datetime
Modul importieren :
import datetime
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__
:
>>> datetime.datetime.now()
datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)
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__
:
>>> print(datetime.datetime.now())
2015-01-24 20:05:44.977951
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:
>>> the_past = datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)
>>> print(the_past)
2015-01-24 20:05:36.491180
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:
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
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:
def __str__(self):
"Convert to string, for str()."
return self.isoformat(sep=' ')
__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.
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.
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:
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'
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 Funktion str()
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 ...
.
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:
class Fraction:
def __init__(self, num, den):
self.__num = num
self.__den = den
def __str__(self):
return '(' + str(self.__num) + '/' + str(self.__den) + ')'
def __repr__(self):
return 'Fraction (' + str(self.__num) + ',' + str(self.__den) + ')'
f = Fraction(1,2)
print('I want to represent the Fraction STRING as ' + str(f)) # (1/2)
print('I want to represent the Fraction OBJECT as ', repr(f)) # Fraction (1,2)
In aller Ehrlichkeit eval(repr(obj))
wird nie verwendet. Wenn Sie es verwenden, sollten Sie aufhören, da dies eval
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 , dass str(list)
Anrufe repr
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ächlicher repr
wird als Ausgabe von wahrscheinlich nicht sehr hilfreich sein print [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 nichts eval
passiert.
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 als unlink
, 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. "
__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 ():
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 .
Aus dem Buch Fluent Python :
Eine Grundvoraussetzung für ein Python-Objekt ist die Bereitstellung verwendbarer Zeichenfolgendarstellungen von sich selbst, eine zum Debuggen und Protokollieren, eine andere zur Präsentation für Endbenutzer. Deshalb sind die
speziellen Methoden__repr__
und__str__
im Datenmodell vorhanden.
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:
def __repr__(self):
return '{0} ({1})'.format(object.__repr__(self), str(self))
Eine wichtige Sache, die zu beachten ist, ist, dass der Container die
__str__
enthaltenen Objekte verwendet__repr__
.
>>> from datetime import datetime
>>> from decimal import Decimal
>>> print (Decimal('52'), datetime.now())
(Decimal('52'), datetime.datetime(2015, 11, 16, 10, 51, 26, 185000))
>>> str((Decimal('52'), datetime.now()))
"(Decimal('52'), datetime.datetime(2015, 11, 16, 10, 52, 22, 176000))"
Python bevorzugt die Eindeutigkeit gegenüber der Lesbarkeit , den __str__
Aufruf eines Aufrufs tuple
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.
__repr__
wenn es ( __str__
) nicht definiert ist! Du liegst also falsch.
In einer Nussschale:
class Demo:
def __repr__(self):
return 'repr'
def __str__(self):
return 'str'
demo = Demo()
print(demo) # use __str__, output 'str' to stdout
s = str(demo) # __str__ is used, return 'str'
r = repr(demo) # __repr__ is used, return 'repr'
import logging
logger = logging.getLogger(logging.INFO)
logger.info(demo) # use __str__, output 'str' to stdout
from pprint import pprint, pformat
pprint(demo) # use __repr__, output 'repr' to stdout
result = pformat(demo) # use __repr__, result is string which value is 'str'
>>> print(decimal.Decimal(23) / decimal.Decimal("1.05"))
21.90476190476190476190476190
>>> decimal.Decimal(23) / decimal.Decimal("1.05")
Decimal('21.90476190476190476190476190')
Wenn print()
aufgerufen wird, wird das Ergebnis decimal.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 eine decimal.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.
__str__
kann durch Aufrufen für ein Objekt aufgerufen werden str(obj)
und sollte eine von Menschen lesbare Zeichenfolge zurückgeben.
__repr__
kann durch Aufrufen für ein Objekt aufgerufen werden repr(obj)
und sollte ein internes Objekt (Objektfelder / Attribute) zurückgeben.
Dieses Beispiel kann helfen:
class C1:pass
class C2:
def __str__(self):
return str(f"{self.__class__.__name__} class str ")
class C3:
def __repr__(self):
return str(f"{self.__class__.__name__} class repr")
class C4:
def __str__(self):
return str(f"{self.__class__.__name__} class str ")
def __repr__(self):
return str(f"{self.__class__.__name__} class repr")
ci1 = C1()
ci2 = C2()
ci3 = C3()
ci4 = C4()
print(ci1) #<__main__.C1 object at 0x0000024C44A80C18>
print(str(ci1)) #<__main__.C1 object at 0x0000024C44A80C18>
print(repr(ci1)) #<__main__.C1 object at 0x0000024C44A80C18>
print(ci2) #C2 class str
print(str(ci2)) #C2 class str
print(repr(ci2)) #<__main__.C2 object at 0x0000024C44AE12E8>
print(ci3) #C3 class repr
print(str(ci3)) #C3 class repr
print(repr(ci3)) #C3 class repr
print(ci4) #C4 class str
print(str(ci4)) #C4 class str
print(repr(ci4)) #C4 class repr
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
In [30]: str(datetime.datetime.now())
Out[30]: '2017-12-07 15:41:14.002752'
Disguised in string form
Bezüglich __repr__
In [32]: datetime.datetime.now()
Out[32]: datetime.datetime(2017, 12, 7, 15, 43, 27, 297769)
Presence in real body which allows to be manipulated directly.
Wir können die __repr__
Ergebnisse bequem arithmetisch bearbeiten.
In [33]: datetime.datetime.now()
Out[33]: datetime.datetime(2017, 12, 7, 15, 47, 9, 741521)
In [34]: datetime.datetime(2017, 12, 7, 15, 47, 9, 741521) - datetime.datetime(2
...: 017, 12, 7, 15, 43, 27, 297769)
Out[34]: datetime.timedelta(0, 222, 443752)
Wenn die Operation auf anwenden __str__
In [35]: '2017-12-07 15:43:14.002752' - '2017-12-07 15:41:14.002752'
TypeError: unsupported operand type(s) for -: 'str' and 'str'
Gibt nur einen Fehler zurück.
Ein anderes Beispiel.
In [36]: str('string_body')
Out[36]: 'string_body' # in string form
In [37]: repr('real_body')
Out[37]: "'real_body'" #its real body hide inside
Ich hoffe, dies hilft Ihnen dabei, konkrete Gründe zu schaffen, um weitere Antworten zu finden.
__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