python example - Unterschied zwischen __str__ und __repr__?




11 Answers

Alex fasste gut zusammen, war aber überraschend zu knapp.

Lassen Sie mich zunächst die wichtigsten Punkte in Alex 'Beitrag wiederholen:

  • Die Standardimplementierung ist unbrauchbar (es ist schwer vorstellbar, welche nicht wäre, aber ja)
  • Ziel ist es, eindeutig zu sein
  • __str__ Ziel ist es, lesbar zu sein
  • Container __str__ verwendet enthaltene Objekte ' __repr__

Die Standardimplementierung ist nutzlos

Dies ist meistens eine Überraschung, da die Standardeinstellungen von Python ziemlich nützlich sind. In diesem Fall haben Sie jedoch einen Standardwert für __repr__ der folgendermaßen __repr__ würde:

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

wäre zu gefährlich gewesen (z. B. zu einfach, um in eine unendliche Rekursion zu gelangen, wenn sich Objekte auf einander beziehen). Also macht Python Cops raus. Beachten Sie, dass es einen Standard gibt, der wahr ist: Wenn __repr__ definiert ist und __str__ nicht, verhält sich das Objekt wie __str__=__repr__ .

In einfachen Worten bedeutet dies: Fast jedes Objekt, das Sie implementieren, sollte über eine funktionale __repr__ , die für das Verständnis des Objekts __repr__ . Die Implementierung von __str__ ist optional: Tun Sie dies, wenn Sie eine " __str__ Print" -Funktionalität benötigen (z. B. von einem Berichtsgenerator verwendet).

Das Ziel von __repr__ ist es, eindeutig zu sein

Lassen Sie mich gleich rauskommen und es sagen - ich glaube nicht an Debugger. Ich weiß nicht wirklich, wie man einen Debugger benutzt, und ich habe noch nie einen ernsthaften verwendet. Darüber hinaus glaube ich, dass der große Fehler bei Debuggern ihre grundlegende Natur ist - die meisten Fehler, die ich debuggen konnte, sind vor langer Zeit in einer weit entfernten Galaxie aufgetreten. Dies bedeutet, dass ich mit religiösem Eifer an den Holzeinschlag glaube. Protokollierung ist das Lebenselixier eines anständigen Fire-and-Forget-Serversystems. Python vereinfacht das Protokollieren: Mit möglicherweise 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, über einen nützlichen Repräsentanten verfügt, sodass Code wie dieser einfach funktioniert. Deshalb kommt die Sache "eval" zum Vorschein: Wenn Sie genügend Informationen haben, dann eval(repr(c))==c , dann wissen Sie alles über c . Wenn das leicht genug ist, zumindest auf unscharfe Weise, dann machen Sie es. Wenn nicht, stellen Sie sicher, dass Sie über genügend Informationen zu c verfügen. 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 - aber es ist eine nützliche Form, um auszudrücken: "Dies ist alles, was Sie über diese Instanz wissen müssen".

Hinweis: Ich habe %r oben verwendet, nicht %s . Sie möchten immer repr() [oder %r Formatierungszeichen, äquivalent] in der __repr__ Implementierung verwenden, oder Sie vereiteln das Ziel des Repros. Sie möchten MyClass(3) und MyClass("3") .

Das Ziel von __str__ ist es, lesbar zu sein

Insbesondere soll es nicht eindeutig sein - beachten Sie, dass str(3)==str("3") . Wenn Sie eine IP-Abstraktion implementieren, ist es genauso gut, wenn die Zeichenfolge 192.168.1.1 angezeigt wird. Bei der Implementierung einer Datums- / Zeitabstraktion kann der str "2010/4/12 15:35:22" usw. sein. Das Ziel ist es, sie so darzustellen, dass ein Benutzer und kein Programmierer sie lesen möchte. Hacken Sie unnötige Ziffern ab, geben Sie vor, eine andere Klasse zu sein - solange es die Lesbarkeit unterstützt, ist es eine Verbesserung.

Container __str__ verwendet enthaltene Objekte ' __repr__

Das scheint überraschend zu sein, nicht wahr? Es ist ein wenig, aber wie wäre es lesbar

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

Sein? Nicht sehr. Insbesondere für die Zeichenfolgen in einem Container wäre es viel zu leicht, die Zeichenfolgendarstellung zu stören. Denken Sie daran, dass sich Python angesichts der Mehrdeutigkeit der Versuchung widersetzt, zu raten. Wenn Sie das obige Verhalten beim Drucken einer Liste wünschen, einfach

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

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

Zusammenfassung

Implementieren Sie __repr__ für jede Klasse, die Sie implementieren. Dies sollte eine zweite Natur sein. Implementieren Sie __str__ wenn Sie der Meinung sind, dass es sinnvoll ist, eine String-Version zu verwenden, die der besseren Lesbarkeit __str__ mehr Mehrdeutigkeit bietet.

__add__ vs

Was ist der Unterschied zwischen __str__ und __repr__ in Python ?




Wenn Sie nicht ausdrücklich etwas anderes tun, haben die meisten Klassen 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 außerhalb der Klassen- und Objekt- id . Wenn Sie nur eine der beiden Einstellungen ü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 __repr__ überschreiben, wird dies auch für __str__ , nicht jedoch umgekehrt.

Weitere wichtige __str__ : __str__ in einem eingebauten Container verwendet __repr__ , NICHT __str__ für die darin enthaltenen Elemente. Und trotz der Wörter zum Thema, die in typischen Dokumenten zu finden sind, __repr__ kaum jemand, dass __repr__ von Objekten eine Zeichenfolge ist, die eval zum Erstellen eines gleichwertigen Objekts verwendet (es ist einfach zu schwer, UND nicht zu wissen, wie das betreffende Modul tatsächlich importiert wurde es ist eigentlich völlig unmöglich).

Mein Rat: Fokussieren Sie sich darauf, __str__ einigermaßen lesbar zu machen und __repr__ so eindeutig wie möglich zu machen, selbst wenn dies das unscharfe, unerreichbare Ziel __repr__ , __repr__ Rückgabewert als Eingabe für __eval__ akzeptabel zu __eval__ !




Kurz gesagt, das Ziel von __repr__ ist eindeutig und __str__ 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 repr:

repr(object)

Gibt eine Zeichenfolge zurück, die eine druckbare Darstellung eines Objekts enthält. Dies ist derselbe Wert, der sich aus Conversions ergibt (umgekehrte Quotes). Es ist manchmal nützlich, auf diesen Vorgang als gewöhnliche Funktion zugreifen zu können. Bei vielen Typen versucht diese Funktion, eine Zeichenfolge zurückzugeben, die ein Objekt mit demselben Wert ergibt, wenn sie an eval() wird. Andernfalls handelt es sich bei der Darstellung um eine in spitze Klammern eingeschlossene Zeichenfolge, die den Namen des Objekttyps enthält mit zusätzlichen Informationen, die häufig den Namen und die Adresse des Objekts enthalten. 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 schön druckbare Darstellung eines Objekts enthält. Bei Strings wird der String selbst zurückgegeben. Der Unterschied zu repr(object) besteht darin, dass str(object) nicht immer versucht, eine Zeichenfolge zurückzugeben, die für eval() zulässig ist. Sein Ziel ist es, eine druckbare Zeichenfolge zurückzugeben. Wenn kein Argument angegeben ist, wird die leere Zeichenfolge '' .




Abgesehen von allen Antworten möchte ich noch 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 der __str__() verwenden.

3) Falls __str__ fehlt, dann print und jede Funktion, die str() ruft __repr__() des Objekts auf.

4) __str__() von Containern führt bei Aufruf die __repr__() Methode der enthaltenen Elemente aus.

5) str() das innerhalb von __str__() aufgerufen wird, könnte möglicherweise ohne Basisfall erneut auftreten und Fehler bei der maximalen Rekursionstiefe.

6) __repr__() kann repr() aufrufen, um automatisch eine unendliche Rekursion zu vermeiden, wobei ein bereits dargestelltes Objekt durch ... .




Um eval(repr(obj)) , wird eval(repr(obj)) niemals verwendet. Wenn Sie feststellen, dass Sie es verwenden, sollten Sie aufhören, da eval gefährlich ist und Strings eine sehr ineffiziente Methode zum Serialisieren Ihrer Objekte sind (verwenden Sie stattdessen pickle ).

Daher würde ich empfehlen, __repr__ = __str__ . Der Grund ist, dass str(list) repr für die Elemente aufruft (ich halte dies für einen der größten Konstruktionsfehler von Python, die von Python 3 nicht angesprochen wurden). Ein tatsächlicher repr wird wahrscheinlich als Ausgabe von print [your, objects] nicht sehr hilfreich sein.

Um dies zu qualifizieren, besteht meiner Meinung nach der nützlichste Anwendungsfall der repr darin, eine Zeichenfolge in eine andere Zeichenfolge einzufügen (unter Verwendung der Zeichenfolgenformatierung). Auf diese Weise müssen Sie sich keine Sorgen um Zitate oder ähnliches machen. Beachten Sie jedoch, dass hier keine eval stattfindet.




Von http://pyref.infogami.com/__str__ durch effbot:

__str__ "berechnet die" informelle "Zeichenfolgendarstellung eines Objekts. Dies unterscheidet sich von __repr__ dass es sich nicht um einen gültigen Python-Ausdruck handeln muss. Stattdessen kann eine bequemere oder prägnantere Darstellung verwendet werden."




str - Erstellt ein neues String-Objekt aus dem angegebenen Objekt.

repr - Gibt die kanonische Zeichenfolgendarstellung des Objekts zurück.

Die Unterschiede:

str ():

  • macht das Objekt lesbar
  • Erzeugt eine Ausgabe für den Endbenutzer

repr ():

  • benötigt Code, der das Objekt reproduziert
  • Erzeugt Ausgabe für Entwickler



Ausgezeichnete Antworten decken bereits den Unterschied zwischen __str__ und __repr__ , was für mich darauf __repr__ , dass erstere sogar für einen Endbenutzer lesbar sind und letztere für Entwickler so nützlich wie möglich ist. In Anbetracht dessen finde ich, dass die Standardimplementierung von __repr__ dieses Ziel häufig nicht erreicht, da für Entwickler nützliche Informationen __repr__ .

Aus diesem Grund versuche ich, wenn ich ein einfaches genug __str__ , im Allgemeinen nur das Beste aus beiden Welten mit etwas wie:

def __repr__(self):
    return '{0} ({1})'.format(object.__repr__(self), str(self))



Es ist wichtig zu wissen, dass __str__ Containers die enthaltenen Objekte __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 der Lesbarkeit , der Aufruf eines tuple __str__ ruft die enthaltenen Objekte __repr__ , die "formale" Darstellung eines Objekts. Obwohl die formale Darstellung schwieriger zu lesen ist als eine informelle, ist sie eindeutig und widerstandsfähiger gegen Fehler.




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'



__repr__ wird überall verwendet, mit Ausnahme von print und str wenn ein __str__ definiert ist




Related

python magic-methods repr