Was ist der Unterschied zwischen __str__
und __repr__
im Python
?
Was ist der Unterschied zwischen __str__
und __repr__
im Python
?
Alex gut zusammengefasst, aber überraschenderweise zu knapp.
Lassen Sie mich zunächst die Hauptpunkte in Alex 'Post:
__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 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))==c
Das 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.
Meine Faustregel: __repr__
ist für Entwickler, __str__
ist für Kunden.
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__
!
__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
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 dasstr(object)
nicht Versuchen Sie immer, eine Zeichenfolge zurückzugeben, die akzeptabel isteval()
; es ist Ziel ist es, eine druckbare Zeichenfolge zurückzugeben. Wenn kein Argument angegeben wird, wird zurückgegeben die leere Zeichenfolge,''
.
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 str
dann, 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.
__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.
__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
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=' ')
__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.
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.
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 ...
.