Was ist der Zweck von __str__ und __repr__?

82

Ich verstehe wirklich nicht, wo __str__und __repr__in Python verwendet. Ich meine, ich bekomme, dass __str__die Zeichenfolgendarstellung eines Objekts zurückgegeben wird. Aber warum sollte ich das brauchen? In welchem ​​Anwendungsfall? Außerdem habe ich über die Verwendung von gelesen__repr__

Aber was ich nicht verstehe ist, wo würde ich sie verwenden?

Daniel
quelle
4
Für jeden, der aus Ruby kommt, ist das tl; dr: __str__= to_sund __repr__= inspect.
Ajedi32

Antworten:

86

__repr__

Wird von der repr()integrierten Funktion und von Zeichenfolgenkonvertierungen (umgekehrte Anführungszeichen) aufgerufen , um die "offizielle" Zeichenfolgendarstellung eines Objekts zu berechnen. Wenn möglich, sollte dies wie ein gültiger Python-Ausdruck aussehen, mit dem ein Objekt mit demselben Wert (in einer geeigneten Umgebung) neu erstellt werden kann.

__str__

Wird von der str()integrierten Funktion und von der print-Anweisung aufgerufen , um die "informelle" Zeichenfolgendarstellung eines Objekts zu berechnen.

Verwenden __str__Sie diese Option, wenn Sie eine Klasse haben und eine informative / informelle Ausgabe wünschen, wenn Sie dieses Objekt als Teil einer Zeichenfolge verwenden. Sie können beispielsweise __str__Methoden für Django-Modelle definieren, die dann in der Django-Verwaltungsoberfläche gerendert werden. Anstelle von so etwas erhalten <Model object>Sie den Vor- und Nachnamen einer Person, den Namen und das Datum eines Ereignisses usw.


__repr__und __str__sind ähnlich, in der Tat manchmal gleich (Beispiel aus der BaseSetKlasse in sets.pyder Standardbibliothek):

def __repr__(self):
    """Return string representation of a set.

    This looks like 'Set([<list of elements>])'.
    """
    return self._repr()

# __str__ is the same as __repr__
__str__ = __repr__
miku
quelle
1
Vielen Dank! Genau das habe ich gesucht!
Daniel
Was `return self._repr ()` bewirkt, wenn ich den Code ausführe und versuche zu verstehen, dass __repr __ () genau ein Argument benötigt.
scheint
Kann ich also __repr__anstelle von __str__Django verwenden?
Amit Tripathi
59

Der einzige Ort, an dem Sie beide häufig verwenden, ist eine interaktive Sitzung. Wenn Sie ein Objekt drucken, wird seine __str__Methode aufgerufen. Wenn Sie nur ein Objekt selbst verwenden, __repr__wird Folgendes angezeigt:

>>> from decimal import Decimal
>>> a = Decimal(1.25)
>>> print(a)
1.25                  <---- this is from __str__
>>> a
Decimal('1.25')       <---- this is from __repr__

Das __str__soll so gut wie möglich lesbar sein, während das__repr__ Ziel sein sollte, etwas zu sein, mit dem das Objekt neu erstellt werden kann, obwohl es oft nicht genau so ist, wie es erstellt wurde, wie in diesem Fall.

Es ist auch nicht ungewöhnlich für beide __str__und __repr__denselben Wert zurück ( auf jeden Fall für integrierte Typen).

Scott Griffiths
quelle
Vielen Dank für das Beispiel, gab mir ein besseres Verständnis dafür, wo dies standardmäßig verwendet wird
JayRizzo
17

Heuschrecke, wenn Sie Zweifel haben, gehen Sie zum Berg und lesen Sie die alten Texte . In ihnen finden Sie, dass __repr __ ():

Wenn möglich, sollte dies wie ein gültiger Python-Ausdruck aussehen, mit dem ein Objekt mit demselben Wert neu erstellt werden kann.

Peter Rowell
quelle
6
-1, da dies nicht einmal versucht, die eigentliche Frage zu beantworten, was die Anwendungsfälle sind.
Scott Griffiths
4
@ Scott: Du bist richtig. Andererseits zeigte die eigentliche Frage absolut keinen Versuch, überhaupt zu den primären Dokumenten zu gelangen. Es ist eine Sache, eine Frage zu stellen, die zeigt, dass Sie versucht haben, sie selbst zu beantworten, aber immer noch ein wenig verwirrt sind, und eine andere Sache, eine Frage wie diese zu posten. Allein die Eingabe seiner Betreffzeile als neue Frage zeigt, dass 5 der Top-6-vorgeschlagenen SO-Threads seine Frage beantwortet hätten, aber er konnte nicht gestört werden. Ich gab ihm keine Antwort, aber ich war sehr versucht.
Peter Rowell
1
Eigentlich hat er gesagt, dass er darüber gelesen hat __repr__, die offiziellen Dokumente beantworten die Frage, warum Sie sie verwenden würden, nicht wirklich, und nur weil eine Frage an anderer Stelle beantwortet wird, ist dies kein guter Grund, es nicht auch zu sein auf SO beantwortet (so oft wie nicht Googeln bringt Sie hierher zurück!) Wenn Sie nicht der Meinung sind, dass die Frage eine Antwort wert ist, können Sie sie einfach nicht beantworten, obwohl ich in diesem Fall zustimme, dass sie bereits sehr gut behandelt wird Eine Verknüpfung mit Duplikaten wäre daher eine angemessene Antwort.
Scott Griffiths
Eigentlich bist du falsch. In den Dokumenten wird ausdrücklich angegeben, warum Sie es verwenden würden: "Dies wird normalerweise zum Debuggen verwendet. Daher ist es wichtig, dass die Darstellung reich an Informationen und eindeutig ist." Ich habe zu viele Foren (Foren?) Gesehen, die unter dem Gewicht von Help Vampires versanken, und es schmerzt mich zu sehen, wie es anfängt, SO weiterzugeben. Die Verknüpfung mit den anderen offensichtlichen SO-Antworten ist der gesamte Zweck des Vorschlagsmechanismus, der beim Eingeben Ihrer Betreffzeile aktiviert wird. Er hat sich jedoch dafür entschieden, alle Vorschläge zu ignorieren. QED & PDQ auch.
Peter Rowell
5
Nun, die Dokumente sagen immer noch nicht, wie man es zum Debuggen verwendet, aber ich hatte wirklich nicht vor, darüber zu streiten. Wir sind uns zumindest einig, dass Ihre Antwort die Frage nicht beantwortet hat, daher fühlt sich mein -1 für mich immer noch gerechtfertigt an. Wenn eine Frage schlecht geschrieben / ein Duplikat / eine Kleinigkeit ist, können Sie helfen, die Frage zu verbessern, auf Duplikate zu verlinken oder die Frage einfach herunterzustimmen. Ich denke, mein Hauptargument hier ist, dass Antworten versuchen sollten, die Frage zu beantworten - es gibt andere Mechanismen, um die Frage zu kritisieren. Ich werde jetzt die Klappe halten, da ich denke, dass wir beide hier bessere Dinge zu tun haben.
Scott Griffiths
14

Aufbauend auf den vorherigen Antworten und Zeigen einiger weiterer Beispiele. Bei sachgemäßer Verwendung ist der Unterschied zwischen strund reprklar. Kurz gesagt, reprsollte eine Zeichenfolge zurückgegeben werden, die kopiert werden kann, um den genauen Status des Objekts wiederherzustellen, während strdies für das Debuggen loggingund observingDebuggen von Ergebnissen nützlich ist . Hier sind einige Beispiele, um die verschiedenen Ausgaben für einige bekannte Bibliotheken zu sehen.

Terminzeit

print repr(datetime.now())    #datetime.datetime(2017, 12, 12, 18, 49, 27, 134411)
print str(datetime.now())     #2017-12-12 18:49:27.134452

Das strist gut, um in eine Protokolldatei zu drucken, wo reprdies zweckentfremdet werden kann, wenn Sie es direkt ausführen oder als Befehle in eine Datei kopieren möchten.

x = datetime.datetime(2017, 12, 12, 18, 49, 27, 134411)

Numpy

print repr(np.array([1,2,3,4,5])) #array([1, 2, 3, 4, 5])
print str(np.array([1,2,3,4,5]))  #[1 2 3 4 5]

in Numpy reprist das wieder direkt verbrauchbar.

Beispiel für einen benutzerdefinierten Vektor3

class Vector3(object):
    def __init__(self, args):
        self.x = args[0]
        self.y = args[1]
        self.z = args[2]

    def __str__(self):
        return "x: {0}, y: {1}, z: {2}".format(self.x, self.y, self.z)

    def __repr__(self):
        return "Vector3([{0},{1},{2}])".format(self.x, self.y, self.z)

In diesem Beispiel wird reprerneut eine Zeichenfolge zurückgegeben, die direkt verwendet / ausgeführt werden kann, während strdies als Debug-Ausgabe nützlicher ist.

v = Vector3([1,2,3])
print str(v)     #x: 1, y: 2, z: 3
print repr(v)    #Vector3([1,2,3])

Eine Sache, die Sie beachten sollten , wird automatisch aufgerufen , wenn sie strnicht definiert reprist . Es ist also immer gut, zumindest zu definierenstrreprrepr

user1767754
quelle
5

Lassen Sie uns eine Klasse ohne __str__Funktion haben.

class Employee:

    def __init__(self, first, last, pay):
        self.first = first 
        self.last = last
        self.pay = pay

emp1 = Employee('Ivan', 'Smith', 90000)

print(emp1)

Wenn wir diese Instanz der Klasse drucken emp1, erhalten wir Folgendes:

<__main__.Employee object at 0x7ff6fc0a0e48>

Dies ist nicht sehr hilfreich, und dies ist sicherlich nicht das, was wir drucken möchten, wenn wir es zur Anzeige verwenden (wie in HTML).

Also jetzt die gleiche Klasse, aber mit __str__Funktion:

class Employee:

    def __init__(self, first, last, pay):
        self.first = first 
        self.last = last
        self.pay = pay

    def __str__(self):
        return(f"The employee {self.first} {self.last} earns {self.pay}.")
        # you can edit this and use any attributes of the class

emp2 = Employee('John', 'Williams', 90000)

print(emp2)

Anstatt zu drucken, dass es ein Objekt gibt, erhalten wir jetzt das, was wir mit der Rückgabe der __str__Funktion angegeben haben:

The employee John Williams earns 90000

Zorana
quelle
3

strwird ein informelles und lesbares Format sein, während repreine offizielle Objektdarstellung gegeben wird.

class Complex:
    # Constructor
    def __init__(self, real, imag):
        self.real = real
        self.imag = imag

    # "official" string representation of an object
    def __repr__(self):
        return 'Rational(%s, %s)' % (self.real, self.imag)

    # "informal" string representation of an object (readable)
    def __str__(self):
        return '%s + i%s' % (self.real, self.imag)

    t = Complex(10, 20)

    print (t)     # this is usual way we print the object
    print (str(t))  # this is str representation of object 
    print (repr(t))  # this is repr representation of object   

Answers : 

Rational(10, 20) # usual representation
10 + i20      # str representation
Rational(10, 20)  # repr representation
Vishvajit Pathak
quelle
1

str und repr sind beide Darstellungsweisen. Sie können sie verwenden, wenn Sie eine Klasse schreiben.

class Fraction:
def __init__(self, n, d):
    self.n = n
    self.d = d
def __repr__(self):
    return "{}/{}".format(self.n, self.d)

Wenn ich beispielsweise eine Instanz davon drucke, werden Dinge zurückgegeben.

print(Fraction(1, 2))

führt zu

1/2

während

class Fraction:
def __init__(self, n, d):
    self.n = n
    self.d = d
def __str__(self):
    return "{}/{}".format(self.n, self.d)
print(Fraction(1, 2))

führt auch zu

1/2

Aber was ist, wenn Sie beide schreiben, welches verwendet Python?

class Fraction:
def __init__(self, n, d):
    self.n = n
    self.d = d
def __str__(self):
    return "str"
def __repr__(self):
    return "repr"

print(Fraction(None, None))

Das führt zu

str

Python verwendet also tatsächlich die str- Methode und nicht die repr- Methode, wenn beide geschrieben sind.

NoahNoahNoah
quelle