Domanda Differenza tra __str__ e __repr__?


Qual è la differenza tra __str__ e __repr__ in Python?


2107
2017-09-17 04:27


origine


risposte:


alex riassunto bene ma, a sorpresa, era troppo sintetico.

Innanzitutto, vorrei ribadire i punti principali di Il post di Alex:

  • L'implementazione predefinita è inutile (è difficile pensarne una che non lo sarebbe, ma si)
  • __repr__ l'obiettivo è essere ambigui
  • __str__ l'obiettivo è essere leggibile
  • contenitore di __str__ usa oggetti contenuti ' __repr__

L'implementazione predefinita è inutile

Questa è principalmente una sorpresa perché i valori predefiniti di Python tendono ad essere abbastanza utili. Tuttavia, in questo caso, per impostazione predefinita __repr__ che si comporterebbe come:

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

sarebbe stato troppo pericoloso (ad esempio, troppo facile entrare in una ricorsione infinita se gli oggetti si richiamano l'un l'altro). Quindi Python si fa avanti. Nota che c'è un default che è vero: if __repr__ è definito, e __str__ non lo è, l'oggetto si comporterà come se __str__=__repr__.

Ciò significa, in termini semplici: quasi ogni oggetto che si implementa dovrebbe avere un funzionale __repr__ è utilizzabile per capire l'oggetto. Implementazione __str__ è facoltativo: fatelo se avete bisogno di una funzionalità di "bella stampa" (ad esempio, utilizzata da un generatore di report).

L'obiettivo di __repr__ deve essere inequivocabile

Lasciami uscire e dillo: non credo nei debuggers. Non so davvero come usare un debugger e non ne ho mai usato uno seriamente. Inoltre, credo che il grosso difetto dei debugger sia la loro natura di base: la maggior parte dei fallimenti ho fatto il debug molto tempo fa, in una galassia molto lontana. Ciò significa che io credo, con fervore religioso, nel logging. Il logging è la linfa vitale di qualsiasi sistema di server decent fire-and-forget. Python semplifica il log: con forse alcuni wrapper specifici per il progetto, tutto ciò che serve è 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)

Ma devi fare l'ultimo passo - assicurati che ogni oggetto che implementi abbia un utile repr, quindi il codice come quello può funzionare. Questo è il motivo per cui la cosa "eval" viene fuori: se hai abbastanza informazioni così eval(repr(c))==csignifica che sai tutto quello che c'è da sapere c. Se è abbastanza facile, almeno in modo sfocato, fallo. In caso contrario, assicurati di avere abbastanza informazioni su c Comunque. Di solito uso un formato simile a Eval: "MyClass(this=%r,that=%r)" % (self.this,self.that). Ciò non significa che tu possa effettivamente costruire MyClass, o che siano gli argomenti giusti per il costruttore, ma è una forma utile per esprimere "questo è tutto ciò che devi sapere su questa istanza".

Nota: l'ho usato %r sopra, no %s. Vuoi sempre usare repr() [o %r carattere di formattazione, equivalentemente] all'interno __repr__ implementazione, o stai sconfiggendo l'obiettivo di repr. Vuoi essere in grado di differenziare MyClass(3) e MyClass("3").

L'obiettivo di __str__ deve essere leggibile

In particolare, non è destinato a essere inequivocabile: notalo str(3)==str("3"). Allo stesso modo, se si implementa un'astrazione IP, avere lo str di esso come 192.168.1.1 va bene. Quando si implementa un'astrazione data / ora, lo str può essere "2010/4/12 15:35:22", ecc. L'obiettivo è rappresentarlo in un modo che un utente, non un programmatore, vorrebbe leggerlo. Taglia le cifre inutili, fai finta di essere un'altra classe - a patto che supporti la leggibilità, è un miglioramento.

contenitore di __str__ usa oggetti contenuti ' __repr__

Questo sembra sorprendente, vero? È un po ', ma sarebbe leggibile

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

essere? Non molto. Nello specifico, le stringhe in un contenitore troverebbero troppo facile disturbare la rappresentazione delle stringhe. Di fronte all'ambiguità, ricorda, Python resiste alla tentazione di indovinare. Se si desidera il comportamento sopra riportato quando si stampa un elenco, solo

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

(probabilmente puoi anche capire cosa fare con i dizionari.

Sommario

Strumento __repr__ per qualsiasi classe che implementa. Questa dovrebbe essere una seconda natura. Strumento __str__ se pensi che sarebbe utile avere una versione di stringa che vada a vantaggio di una maggiore leggibilità a favore di una maggiore ambiguità.


2171
2018-04-13 00:56



La mia regola generale: __repr__ è per sviluppatori, __str__ è per i clienti.


368
2017-09-17 11:35



A meno che non si agisca in modo specifico per garantire il contrario, la maggior parte delle classi non ha risultati utili per:

>>> class Sic(object): pass
... 
>>> print str(Sic())
<__main__.Sic object at 0x8b7d0>
>>> print repr(Sic())
<__main__.Sic object at 0x8b7d0>
>>> 

Come vedi, nessuna differenza e nessuna informazione al di là della classe e dell'oggetto id. Se si sostituisce solo uno dei due ...:

>>> 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>
>>> 

come vedi, se hai la precedenza __repr__, questo è ANCHE usato per __str__, ma non viceversa.

Altre curiosità da sapere: __str__ su un contenitore integrato usa il __repr__, Non il __str__, per gli oggetti che contiene. E, nonostante le parole sull'argomento trovate nei documenti tipici, quasi nessuno si preoccupa di fare il __repr__ di oggetti essere una stringa che eval può essere usato per costruire un oggetto uguale (è troppo difficile, E non sapere come il modulo rilevante è stato effettivamente importato lo rende effettivamente impossibile).

Quindi, il mio consiglio: concentrarsi sulla realizzazione __str__ ragionevolmente leggibile dall'uomo, e __repr__ il più chiaramente possibile, anche se ciò interferisce con lo sfocato obiettivo irraggiungibile del fare __repr__Il valore restituito è accettabile come input per __eval__!


318
2017-09-17 04:49



__repr__: la rappresentazione dell'oggetto python di solito eval la convertirà nuovamente in quell'oggetto

__str__: è qualunque cosa tu pensi sia quell'oggetto in forma di testo

per esempio.

>>> 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

143
2017-09-17 04:35



In breve, l'obiettivo di __repr__ deve essere inequivocabile e __str__ deve essere   leggibile.

Ecco un buon esempio:

>>> 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)'

Leggi questa documentazione per repr:

repr(object)

Restituisce una stringa contenente una rappresentazione stampabile di un oggetto. Questo è lo stesso valore prodotto dalle conversioni (inverso   citazioni). A volte è utile poter accedere a questa operazione come   una funzione ordinaria. Per molti tipi, questa funzione fa un tentativo   per restituire una stringa che restituirebbe un oggetto con lo stesso valore quando   passato a eval(), altrimenti la rappresentazione è una stringa racchiusa in   parentesi angolari che contiene il nome del tipo dell'oggetto   insieme con informazioni aggiuntive spesso incluso il nome e   indirizzo dell'oggetto. Una classe può controllare ciò che restituisce questa funzione   per le sue istanze definendo a __repr__() metodo.

Ecco la documentazione per str:

str(object='')

Restituisce una stringa che contiene un grazioso stampabile   rappresentazione di un oggetto. Per le stringhe, restituisce la stringa   si. La differenza con repr(object)è questo str(object) non   tenta sempre di restituire una stringa accettabile eval(); suo   l'obiettivo è restituire una stringa stampabile. Se non viene fornito alcun argomento, restituisce   la stringa vuota, ''.


114
2017-10-25 18:38



Qual è la differenza tra __str__ e __repr__ in Python?

__str__ (leggi come "dunder (double-underscore) string") e __repr__ (leggi come "dunder-repper" (per "rappresentazione")) sono entrambi metodi speciali che restituiscono stringhe in base allo stato dell'oggetto.

__repr__ fornisce un comportamento di backup se __str__ manca.

Quindi si dovrebbe prima scrivere a __repr__ ciò ti consente di reinstantiare un oggetto equivalente dalla stringa che restituisce, ad es. utilizzando eval o digitandolo in carattere per carattere in una shell Python.

In qualsiasi momento più tardi, si può scrivere a __str__ per una rappresentazione di stringa leggibile dall'utente dell'istanza, quando si ritiene che sia necessaria.

__str__

Se si stampa un oggetto o lo si passa a format, str.format, o str, quindi se a __str__ metodo è definito, quel metodo sarà chiamato, altrimenti, __repr__ sarà usato.

__repr__

Il __repr__ il metodo è chiamato dalla funzione builtin repr ed è ciò che viene echeggiato nella tua shell python quando valuta un'espressione che restituisce un oggetto.

Dal momento che fornisce un backup per __str__, se puoi scriverne solo uno, inizia con __repr__

Ecco l'aiuto integrato su repr:

repr(...)
    repr(object) -> string

    Return the canonical string representation of the object.
    For most object types, eval(repr(object)) == object.

Cioè, per la maggior parte degli oggetti, se digiti ciò che è stampato da repr, dovresti essere in grado di creare un oggetto equivalente. Ma questa non è l'implementazione predefinita.

Implementazione di default di __repr__

L'oggetto predefinito __repr__ è (C Python source) qualcosa di simile a:

def __repr__(self):
    return '<{0}.{1} object at {2}>'.format(
      self.__module__, type(self).__name__, hex(id(self)))

Ciò significa che di default stamperai il modulo da cui proviene l'oggetto, il nome della classe e la rappresentazione esadecimale della sua posizione in memoria, ad esempio:

<__main__.Foo object at 0x7f80665abdd0>

Questa informazione non è molto utile, ma non c'è modo di ricavare come si possa creare accuratamente una rappresentazione canonica di una data istanza, ed è meglio di niente, almeno dicendoci come possiamo identificarla in modo univoco nella memoria.

Come può __repr__ essere utile?

Diamo un'occhiata a quanto può essere utile, usando la shell Python e datetime oggetti. Per prima cosa dobbiamo importare il datetime modulo:

import datetime

Se chiamiamo datetime.now nella shell, vedremo tutto ciò di cui abbiamo bisogno per ricreare un oggetto datetime equivalente. Questo è creato dal datetime __repr__:

>>> datetime.datetime.now()
datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)

Se stampiamo un oggetto datetime, vediamo un bel formato leggibile dall'uomo (in effetti, ISO). Questo è implementato da datetime __str__:

>>> print(datetime.datetime.now())
2015-01-24 20:05:44.977951

È semplice ricreare l'oggetto che abbiamo perso perché non l'abbiamo assegnato a una variabile copiando e incollando dal __repr__ output, quindi stamparlo e lo otteniamo nella stessa uscita leggibile dall'uomo dell'altro oggetto:

>>> the_past = datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)
>>> print(the_past)
2015-01-24 20:05:36.491180

Come li realizzo?

Mentre stai sviluppando, dovrai essere in grado di riprodurre oggetti nello stesso stato, se possibile. Questo, ad esempio, è come definisce l'oggetto datetime __repr__ (Fonte Python). È abbastanza complesso, a causa di tutti gli attributi necessari per riprodurre un tale oggetto:

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

Se vuoi che il tuo oggetto abbia una rappresentazione più leggibile, puoi implementarlo __str__ Il prossimo. Ecco come l'oggetto datetime (Fonte Pythonstrumenti __str__, che fa facilmente perché ha già una funzione per visualizzarlo in formato ISO:

def __str__(self):
    "Convert to string, for str()."
    return self.isoformat(sep=' ')

Impostato __repr__ = __str__?

Questa è una critica di un'altra risposta qui che suggerisce di ambientare __repr__ = __str__.

Ambientazione __repr__ = __str__ è sciocco - __repr__ è un fallback per __str__ e a __repr__, scritto per l'uso degli sviluppatori nel debug, dovrebbe essere scritto prima di scrivere a __str__.

Avete bisogno di un __str__ solo quando hai bisogno di una rappresentazione testuale dell'oggetto.

Conclusione

Definire __repr__ per gli oggetti che scrivi così tu e gli altri sviluppatori hai un esempio riproducibile quando lo usi mentre sviluppi. Definire __str__ quando hai bisogno di una rappresentazione in stringa leggibile da parte di esso.


84
2018-01-25 02:01



Oltre a tutte le risposte fornite, vorrei aggiungere alcuni punti:

1) __repr__() viene invocato quando si scrive semplicemente il nome dell'oggetto sulla console python interattiva e si preme invio.

2) __str__() viene invocato quando si utilizza l'oggetto con l'istruzione print.

3) Nel caso, se __str__ manca, quindi stampa e qualsiasi funzione utilizza str() invoca __repr__() di oggetto.

4) __str__() dei contenitori, quando invocato verrà eseguito __repr__() metodo dei suoi elementi contenuti.

5) str() chiamato dentro __str__() potrebbe potenzialmente recurse senza un caso base e errore sulla massima profondità di ricorsione.

6) __repr__() puoi chiamare repr() che tenterà di evitare automaticamente la ricorsione infinita, sostituendo un oggetto già rappresentato con ....


12
2017-09-08 03:27