python__repr__ example




Differenza tra__str__ e__repr__? (14)

Qual è la differenza tra __str__ e __repr__ in Python ?


Qual è la differenza tra __str__ e __repr__ in Python?

__str__ (leggi come "dunder (double-underscore) stringa") 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 manca __str__ .

Quindi si dovrebbe prima scrivere un __repr__ che ti permetta di ricostituire un oggetto equivalente dalla stringa che restituisce, ad esempio usando eval o digitandolo in carattere-per-carattere in una shell Python.

In qualsiasi momento, è possibile scrivere un __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 , allora se viene definito un metodo __str__ , verrà chiamato quel metodo, altrimenti verrà usato __repr__ .

__repr__

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

Poiché fornisce un backup per __str__ , se puoi scriverne solo uno, inizia con __repr__

Ecco l'aiuto repr 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 riuscire a creare un oggetto equivalente. Ma questa non è l'implementazione predefinita.

Implementazione predefinita di __repr__

L'oggetto predefinito __repr__ è ( sorgente Python C ) qualcosa del tipo:

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 gli oggetti datetime . Per prima cosa dobbiamo importare il modulo datetime :

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 __str__ di datetime:

>>> 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 dall'output __repr__ e quindi stampandolo, e lo otteniamo nello stesso output leggibile come l'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 l'oggetto datetime definisce __repr__ ( origine 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 implementare __str__ next. Ecco come l'oggetto datetime ( sorgente Python ) implementa __str__ , cosa 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=' ')

Imposta __repr__ = __str__ ?

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

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

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

Conclusione

Definisci __repr__ per gli oggetti che scrivi in ​​modo tale che tu e altri sviluppatori abbiate un esempio riproducibile quando lo usate durante lo sviluppo. Definisci __str__ quando hai bisogno di una rappresentazione di stringa leggibile dall'uomo.


In breve, l'obiettivo di __repr__ è di essere non ambiguo 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 (virgolette inverse). A volte è utile poter accedere a questa operazione come una funzione ordinaria. Per molti tipi, questa funzione fa un tentativo di restituire una stringa che produce un oggetto con lo stesso valore quando viene passato a eval() , altrimenti la rappresentazione è una stringa racchiusa tra parentesi angolari che contiene il nome del tipo dell'oggetto con informazioni aggiuntive spesso incluso il nome e l'indirizzo dell'oggetto. Una classe può controllare ciò che questa funzione restituisce per le sue istanze definendo un __repr__() .

Ecco la documentazione per str:

str(object='')

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


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 oltre la classe e l' id dell'oggetto. 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 si sostituisce __repr__ , questo è ANCHE usato per __str__ , ma non viceversa.

Altre curiosità da sapere: __str__ su un contenitore __repr__ usa __repr__ , NON il __str__ , per gli elementi che contiene. E, nonostante le parole sull'argomento trovate nei documenti tipici, difficilmente qualcuno che fa il __repr__ degli oggetti sia una stringa che eval può usare per costruire un oggetto uguale (è troppo difficile, E non sapere come il modulo rilevante è stato effettivamente importato fa in realtà è assolutamente impossibile).

Quindi, il mio consiglio: concentrarsi sul rendere __str__ ragionevolmente leggibile e __repr__ più ambiguo possibile, anche se questo interferisce con lo sfocato obiettivo irraggiungibile di rendere il valore restituito di __eval__ come input per __eval__ !


A pagina 358 del libro Python scripting for computational science di Hans Petter Langtangen, lo afferma chiaramente

  • Il __repr__ mira a una rappresentazione completa della stringa dell'oggetto;
  • Il __str__ è di restituire una bella stringa per la stampa.

Quindi, preferisco capirli come

  • repr = riprodurre
  • str = string (rappresentazione)

dal punto di vista dell'utente, anche se questo è un equivoco che ho fatto quando ho imparato Python.

Un piccolo ma buono esempio è anche dato sulla stessa pagina come segue:

Esempio

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'

Da http://pyref.infogami.com/__str__ di effbot:

__str__ "calcola la rappresentazione stringa" informale "di un oggetto, che differisce da __repr__ in quanto non deve essere un'espressione Python valida: al suo posto può essere usata una rappresentazione più comoda o concisa."


In poche parole:

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'

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


Molto più chiaro dal blog

str è come toString. creato in modo da poter stampare i dati repr è come serializzare, o sottaceto. Come posso ricreare questo oggetto se ho bisogno di farlo usando eval ()

>>> import datetime
>>> now = datetime.datetime.now() 
>>> str(now)
'2015-04-04 20:51:31.766862'
>>> repr(now)
'datetime.datetime(2015, 4, 4, 20, 51, 31, 766862)'
>>mydate = eval(repr(now))

Per dirla semplicemente:

__str__ è usato per mostrare una rappresentazione di stringa dell'oggetto da leggere facilmente da altri.

__repr__ è usato per mostrare una rappresentazione di stringa dell'oggetto.

Diciamo che voglio creare una classe Fraction cui la rappresentazione della stringa di una frazione è '(1/2)' e l'oggetto (classe Fraction) deve essere rappresentato come 'Fraction (1,2)'

Quindi possiamo creare una classe Fraction semplice:

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)

Risposte eccellenti coprono già la differenza tra __str__ e __repr__ , che per me si riduce al precedente essendo leggibile anche da un utente finale, e quest'ultimo è il più utile possibile agli sviluppatori. __repr__ questo, trovo che l'implementazione predefinita di __repr__ spesso non riesca a raggiungere questo obiettivo perché omette le informazioni utili agli sviluppatori.

Per questo motivo, se ho un __str__ abbastanza semplice, in genere cerco semplicemente di ottenere il meglio da entrambi i mondi con qualcosa di simile:

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

__repr__ è usato ovunque, tranne da print e str quando è definito __str__


str - Crea un nuovo oggetto stringa dall'oggetto specificato.

repr - Restituisce la rappresentazione di stringa canonica dell'oggetto.

Le differenze:

str ():

  • rende l'oggetto leggibile
  • genera output per l'utente finale

repr ():

  • ha bisogno del codice che riproduce l'oggetto
  • genera output per sviluppatore

Alex riassunse bene ma, a sorpresa, era troppo sintetico.

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

  • L'implementazione predefinita è inutile (è difficile pensarne una che non lo sarebbe, ma si)
  • __repr__ obiettivo __repr__ è essere ambigui
  • __str__ obiettivo __str__ deve essere leggibile
  • Il __str__ contenitore utilizza 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, avente un valore predefinito per __repr__ che si comporta 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: se __repr__ è definito, e __str__ no, l'oggetto si comporterà come se __str__=__repr__ .

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

L'obiettivo di __repr__ è di essere non ambigui

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 in modo eval(repr(c))==c , ciò significa che sai tutto ciò che c'è da sapere su 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: ho usato %r sopra, non %s . Si vuole sempre usare repr() [o %r carattere di formattazione, equivalentemente] all'interno dell'implementazione __repr__ , o si sta sconfiggendo l'obiettivo di repr. Vuoi essere in grado di differenziare MyClass(3) e MyClass("3") .

L'obiettivo di __str__ è quello di essere leggibile

In particolare, non è destinato a essere non ambiguo - si noti che 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.

Il __str__ contenitore utilizza 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

Implementa __repr__ per qualsiasi classe implementata. Questa dovrebbe essere una seconda natura. Implementa __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à.


"A basic requirement for a Python object is to provide usable 
 string   representations of itself, one used for debugging and
 logging, another for presentation to end users. That is why the  
 special methods __repr__ and __str__ exist in the data model."

Dal libro: Fluent Python







repr