Pregunta

¿Cuál es la diferencia entre __str__ y __repr__ en Python?

¿Fue útil?

Solución

Alex resumió bien pero, sorprendentemente, fue demasiado sucinto.

Primero, permítanme reiterar los puntos principales en publicación de Alex :

  • La implementación predeterminada es inútil (es difícil pensar en una que no sería, pero sí)
  • El objetivo de
  • __repr__ es ser inequívoco
  • El objetivo
  • __str__ es ser legible
  • Contenedor & # 8217; s __str__ utiliza objetos contenidos & # 8217; __repr__

La implementación predeterminada es inútil

Esto es principalmente una sorpresa porque los valores predeterminados de Python tienden a ser bastante útiles. Sin embargo, en este caso, tener un valor predeterminado para __repr__ que actuaría como:

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

habría sido demasiado peligroso (por ejemplo, demasiado fácil entrar en una recursión infinita si los objetos se refieren entre sí). Entonces Python se las arregla. Tenga en cuenta que hay un valor predeterminado que es verdadero: si __repr__ está definido y __str__ no lo está, el objeto se comportará como si __str __ = __ repr__ .

Esto significa, en términos simples: casi todos los objetos que implemente deben tener un __repr__ funcional que se pueda usar para comprender el objeto. La implementación de __str__ es opcional: hágalo si necesita una & # 8220; impresión bonita & # 8221; funcionalidad (por ejemplo, utilizada por un generador de informes).

El objetivo de __repr__ es ser inequívoco

Déjame salir y decirlo & # 8212; No creo en depuradores. Realmente no sé cómo usar ningún depurador, y nunca he usado uno en serio. Además, creo que la gran falla en los depuradores es su naturaleza básica & # 8212; La mayoría de las fallas que depuro sucedieron hace mucho, mucho tiempo, en una galaxia muy, muy lejana. Esto significa que sí creo, con fervor religioso, en la tala. El registro es el elemento vital de cualquier sistema de servidor decente para disparar y olvidar. Python facilita el registro: tal vez con algunos contenedores específicos del proyecto, todo lo que necesita es un

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)

Pero tienes que hacer el último paso & # 8212; asegúrese de que cada objeto que implemente tenga una repr útil, por lo que un código como ese puede funcionar. Es por eso que el & # 8220; eval & # 8221; surge: si tiene suficiente información, entonces eval (repr (c)) == c , eso significa que sabe todo lo que hay que saber sobre c . Si eso es lo suficientemente fácil, al menos de manera difusa, hágalo. De lo contrario, asegúrese de tener suficiente información sobre c de todos modos. Usualmente uso un formato de evaluación: " MyClass (this =% r, that =% r) " % (self.this, self.that) . No significa que pueda construir MyClass, o que esos sean los argumentos de constructor correctos & # 8212; pero es una forma útil de expresar & # 8220; esto es todo lo que necesita saber sobre esta instancia & # 8221 ;.

Nota: Utilicé % r arriba, no % s . Siempre desea utilizar repr () [o % r carácter de formato, de manera equivalente] dentro de la implementación de __repr__ , o si está derrotando el objetivo de repr. Desea poder diferenciar MyClass (3) y MyClass (" 3 ") .

El objetivo de __str__ es ser legible

Específicamente, no pretende ser inequívoco & # 8212; observe que str (3) == str (" 3 ") . Del mismo modo, si implementa una abstracción de IP, hacer que la cadena se vea como 192.168.1.1 está bien. Al implementar una abstracción de fecha / hora, el str puede ser "2010/4/12 15: 35: 22", etc. El objetivo es representarlo de manera que un usuario, no un programador, quiera leerlo . Cortar dígitos inútiles, pretender ser otra clase & # 8212; siempre y cuando sea compatible con la legibilidad, es una mejora.

Conta

Otros consejos

Mi regla general: __repr__ es para desarrolladores, __str__ es para clientes.

A menos que actúes específicamente para asegurarte de lo contrario, la mayoría de las clases no tienen resultados útiles para:

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

Como puede ver, no hay diferencia, y no hay información más allá de la id de la clase y el objeto. Si solo anula uno de los dos ...:

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

como ve, si anula __repr__ , TAMBIÉN se usa para __str__ , pero no al revés.

Otros datos cruciales que debe conocer: __str__ en un contenedor incorporado utiliza el __repr__ , NO el __str__ , para los elementos que contiene . Y, a pesar de las palabras sobre el tema que se encuentran en los documentos típicos, casi nadie se molesta en hacer que el __repr__ sea una cadena que eval puede usar para construir un objeto igual (es solo demasiado difícil, Y no saber cómo se importó realmente el módulo relevante hace que sea realmente imposible).

Entonces, mi consejo: concéntrese en hacer que __str__ sea razonablemente legible para los humanos, y __repr__ lo más ambiguo posible, incluso si eso interfiere con el objetivo difuso e inalcanzable de haciendo que el valor devuelto de __repr__ sea aceptable como entrada para __eval__ !

__repr__ : la representación del objeto Python generalmente eval lo convertirá de nuevo en ese objeto

__str__ : es lo que creas que es ese objeto en forma de texto

por ejemplo

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

En resumen, el objetivo de __repr__ es ser inequívoco y __str__ es   legible.

Aquí hay un buen ejemplo:

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

Lea esta documentación para repr:

  

repr(object)

     

Devuelve una cadena que contiene una representación imprimible de un objeto. Este es el mismo valor producido por las conversiones (inversa   citas). A veces es útil poder acceder a esta operación como   Una función ordinaria. Para muchos tipos, esta función hace un intento   para devolver una cadena que produciría un objeto con el mismo valor cuando   pasado a eval () , de lo contrario, la representación es una cadena encerrada en   corchetes angulares que contienen el nombre del tipo de objeto   junto con información adicional que a menudo incluye el nombre y   Dirección del objeto. Una clase puede controlar lo que devuelve esta función   para sus instancias definiendo un método __repr __ () .

Aquí está la documentación para str:

  

str(object='')

     

Devuelve una cadena que contiene un muy bien imprimible   Representación de un objeto. Para cadenas, esto devuelve la cadena   sí mismo. La diferencia con repr (objeto) es que str (objeto) no   siempre intente devolver una cadena que sea aceptable para eval () ; sus   El objetivo es devolver una cadena imprimible. Si no se da ningún argumento, devuelve   la cadena vacía, '' .

  

¿Cuál es la diferencia entre __str__ y __repr__ en Python?

__str__ (leer como " cadena de dunder (subrayado doble) ") y __repr__ (leer como " dunder-repper " (para " representación ") ) son métodos especiales que devuelven cadenas según el estado del objeto.

__repr__ proporciona un comportamiento de respaldo si falta __str__ .

Entonces, primero se debe escribir un __repr__ que le permita reinstalar un objeto equivalente de la cadena que devuelve, p. usando eval o escribiéndolo carácter por carácter en un shell de Python.

En cualquier momento posterior, se puede escribir un __str__ para una representación de cadena legible por el usuario de la instancia, cuando se cree que es necesario.

__str__

Si imprime un objeto o lo pasa a format , str.format o str , entonces si un __str__ se define el método, se llamará a ese método; de lo contrario, se utilizará __repr__ .

__repr__

El método __repr__ es llamado por la función integrada repr y es lo que se repite en su shell de Python cuando evalúa una expresión que devuelve un objeto.

Dado que proporciona una copia de seguridad para __str__ , si solo puede escribir una, comience con __repr__

Aquí está la ayuda integrada en repr :

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

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

Es decir, para la mayoría de los objetos, si escribe lo que imprime repr , debería poder crear un objeto equivalente. Pero esta no es la implementación predeterminada.

Implementación predeterminada de __repr__

El objeto predeterminado __repr__ es ( fuente C Python ) algo así como:

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

Eso significa que, de forma predeterminada, imprimirá el módulo del objeto, el nombre de la clase y la representación hexadecimal de su ubicación en la memoria, por ejemplo:

<__main__.Foo object at 0x7f80665abdd0>

Esta información no es muy útil, pero no hay forma de deducir cómo se puede crear con precisión una representación canónica de una instancia determinada, y es mejor que nada, al menos diciéndonos cómo podríamos identificarla de manera única en la memoria.

¿Cómo puede ser útil __repr__ ?

Veamos qué tan útil puede ser, usando el shell Python y los objetos datetime . Primero necesitamos importar el módulo datetime :

import datetime

Si llamamos a datetime.now en el shell, veremos todo lo que necesitamos para recrear un objeto datetime equivalente. Esto es creado por la fecha y hora __repr__ :

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

Si imprimimos un objeto de fecha y hora, vemos un buen formato legible por humanos (de hecho, ISO). Esto se implementa mediante __str__ de fecha y hora:

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

Es simple recrear el objeto que perdimos porque no lo asignamos a una variable copiando y pegando desde la salida __repr__ , y luego imprimiéndolo, y lo ingresamos la misma salida legible por humanos que el otro objeto:

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

¿Cómo los implemento?

A medida que desarrolla, querrá poder reproducir objetos en el mismo estado, si es posible. Así, por ejemplo, así es como el objeto datetime define __repr__ ( fuente de Python ). Es bastante complejo, debido a todos los atributos necesarios para reproducir dicho objeto:

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 = "%s.%s(%s)" % (self.__class__.__module__,
                       self.__class__.__qualname__,
                       ", ".join(map(str, L)))
    if self._tzinfo is not None:
        assert s[-1:] == ")"
        s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
    if self._fold:
        assert s[-1:] == ")"
        s = s[:-1] + ", fold=1)"
    return s

Si desea que su objeto tenga una representación más legible para los humanos, puede implementar __str__ a continuación. Así es como el objeto datetime (

Además de todas las respuestas dadas, me gustaría agregar algunos puntos: -

1) __repr __ () se invoca cuando simplemente escribe el nombre del objeto en la consola interactiva de Python y presiona enter.

2) __str __ () se invoca cuando utiliza un objeto con una declaración de impresión.

3) En caso de que falte __str__ , imprima y cualquier función que use str () invoca __repr __ () del objeto.

4) __str __ () de contenedores, cuando se invoca ejecutará el método __repr __ () de sus elementos contenidos.

5) str () llamado dentro de __str __ () podría repetirse sin un caso base y un error en la profundidad máxima de recursión.

6) __repr __ () puede llamar a repr () que intentará evitar la recursión infinita automáticamente, reemplazando un objeto ya representado con ... .

En la página 358 del libro Scripting de Python para ciencia computacional de Hans Petter Langtangen, establece claramente que

  • El __repr__ apunta a una representación de cadena completa del objeto;
  • El __str__ es devolver una buena cadena para imprimir.

Entonces, prefiero entenderlos como

  • repr = reproducir
  • str = string (representación)

desde el punto de vista del usuario aunque este es un malentendido que hice al aprender Python.

También se da un pequeño pero buen ejemplo en la misma página de la siguiente manera:

Ejemplo

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'

Honestamente, eval (repr (obj)) nunca se usa. Si lo usa, debe detenerse, porque eval es peligroso, y las cadenas son una forma muy ineficiente de serializar sus objetos (use pickle en su lugar).

Por lo tanto, recomendaría configurar __repr__ = __str__ . La razón es que str (list) llama a repr en los elementos (considero que este es uno de los mayores defectos de diseño de Python que no fue abordado por Python 3). Un repr real probablemente no será muy útil como salida de print [your, objects] .

Para calificar esto, en mi experiencia, el caso de uso más útil de la función repr es colocar una cadena dentro de otra cadena (usando el formato de cadena). De esta manera, no tiene que preocuparse por escapar de citas ni nada. Pero tenga en cuenta que no hay eval sucediendo aquí.

En pocas palabras:

__str__ se utiliza para mostrar una representación de cadena de su objeto para que otros lo puedan leer fácilmente .

__repr__ se usa para mostrar una representación de cadena de el objeto .

Digamos que quiero crear una clase Fraction donde la representación de cadena de una fracción es '(1/2)' y el objeto (clase Fraction) se representará como 'Fraction (1) , 2) '

Para que podamos crear una clase de fracción simple:

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)

De un Wiki de referencia de Python (no oficial) (copia de archivo) por effbot:

__str__ " calcula el " informal " representación en cadena de un objeto. Esto difiere de __repr__ en que no tiene que ser una expresión Python válida: en su lugar, se puede usar una representación más conveniente o concisa. "

Un aspecto que falta en otras respuestas. Es cierto que en general el patrón es:

  • Objetivo de __str__ : legible para humanos
  • Objetivo de __repr__ : inequívoco, posiblemente legible por máquina a través de eval

Desafortunadamente, esta diferenciación es defectuosa, ya que Python REPL y también IPython usan __repr__ para imprimir objetos en una consola REPL (consulte las preguntas relacionadas para Python y IPython ). Por lo tanto, los proyectos destinados al trabajo de la consola interactiva (por ejemplo, Numpy o Pandas) han comenzado a ignorar las reglas anteriores y a proporcionar una implementación __repr__ legible para los humanos.

str : crea un nuevo objeto de cadena a partir del objeto dado.

repr : devuelve la representación de cadena canónica del objeto.

Las diferencias:

str():

  • hace que el objeto sea legible
  • genera resultados para el usuario final

repr():

  • necesita código que reproduzca el objeto
  • genera resultados para el desarrollador

Las respuestas excelentes ya cubren la diferencia entre __str__ y __repr__ , lo que para mí se reduce a que el primero sea legible incluso para un usuario final, y el último sea tan útil como sea posible para los desarrolladores. Dado eso, creo que la implementación predeterminada de __repr__ a menudo no logra este objetivo porque omite información útil para los desarrolladores.

Por esta razón, si tengo un __str__ lo suficientemente simple, generalmente trato de obtener lo mejor de ambos mundos con algo como:

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

Del libro Fluent Python :

  

Un requisito básico para un objeto Python es proporcionar uso        representaciones de cadena de sí mismo, uno usado para depurar y        registro, otro para presentación a usuarios finales. Por eso el
       métodos especiales __repr__ y __str__ existen en el modelo de datos.

  

Una cosa importante a tener en cuenta es que el __str__ del contenedor utiliza los objetos contenidos __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 favorece la ambigüedad sobre la legibilidad , la llamada __str__ de una tuple llama a los objetos contenidos ' __repr__ , la representación " formal " de un objeto. Aunque la representación formal es más difícil de leer que la informal, es inequívoca y más robusta contra los errores.

En pocas palabras:

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'
>>> print(decimal.Decimal(23) / decimal.Decimal("1.05"))
21.90476190476190476190476190
>>> decimal.Decimal(23) / decimal.Decimal("1.05")
Decimal('21.90476190476190476190476190')

Cuando se invoca print () en el resultado de decimal.Decimal (23) / decimal.Decimal (" 1.05 ") se imprime el número sin procesar; esta salida está en forma de cadena que se puede lograr con __str __ () . Si simplemente ingresamos la expresión, obtenemos una salida decimal.Decimal : esta salida está en forma de representación que se puede lograr con __repr __ () . Todos los objetos de Python tienen dos formas de salida. La forma de cadena está diseñada para ser legible por humanos. La forma de representación está diseñada para producir resultados que, si se alimentan a un intérprete de Python, (cuando sea posible) reproducirían el objeto representado.

Comprenda __str__ y __repr__ para distinguirlos intuitiva y permanentemente.

__str__ devuelve el cuerpo encubierto de cadena de un objeto dado para que los ojos puedan leerlo
__repr__ devuelve el cuerpo real de un objeto dado (se devuelve a sí mismo) para que no se identifique la ambigüedad.

Véalo en un ejemplo

In [30]: str(datetime.datetime.now())
Out[30]: '2017-12-07 15:41:14.002752'
Disguised in string form

En cuanto a __repr__

In [32]: datetime.datetime.now()
Out[32]: datetime.datetime(2017, 12, 7, 15, 43, 27, 297769)
Presence in real body which allows to be manipulated directly.

Podemos realizar operaciones aritméticas en los resultados de __repr__ convenientemente.

In [33]: datetime.datetime.now()
Out[33]: datetime.datetime(2017, 12, 7, 15, 47, 9, 741521)
In [34]: datetime.datetime(2017, 12, 7, 15, 47, 9, 741521) - datetime.datetime(2
    ...: 017, 12, 7, 15, 43, 27, 297769)
Out[34]: datetime.timedelta(0, 222, 443752)

si aplica la operación en __str__

In [35]: '2017-12-07 15:43:14.002752' - '2017-12-07 15:41:14.002752'
TypeError: unsupported operand type(s) for -: 'str' and 'str'

Devuelve nada más que error.

Otro ejemplo.

In [36]: str('string_body')
Out[36]: 'string_body' # in string form

In [37]: repr('real_body')
Out[37]: "'real_body'" #its real body hide inside

Espero que esto te ayude a construir bases concretas para explorar más respuestas.

__repr__ se usa en todas partes, excepto por los métodos print y str (cuando se define un __str__ )

  1. __str__ debe devolver un objeto de cadena mientras que __repr__ puede devolver cualquier expresión de Python.
  2. Si falta la implementación __str__ , entonces la función __repr__ se usa como reserva. No hay respaldo si falta la implementación de la función __repr__ .
  3. Si la función __repr__ devuelve una representación de cadena del objeto, podemos omitir la implementación de la función __str__ .

Fuente: https://www.journaldev.com/22460/python -str-repr-functions

__str__ se puede invocar en un objeto llamando a str (obj) y debe devolver una cadena legible por humanos.

__repr__ se puede invocar en un objeto llamando a repr (obj) y debe devolver un objeto interno (campos de objeto / atributos)

Este ejemplo puede ayudar:

class C1:pass

class C2:        
    def __str__(self):
        return str(f"{self.__class__.__name__} class str ")

class C3:        
    def __repr__(self):        
         return str(f"{self.__class__.__name__} class repr")

class C4:        
    def __str__(self):
        return str(f"{self.__class__.__name__} class str ")
    def __repr__(self):        
         return str(f"{self.__class__.__name__} class repr")


ci1 = C1()    
ci2 = C2()  
ci3 = C3()  
ci4 = C4()

print(ci1)       #<__main__.C1 object at 0x0000024C44A80C18>
print(str(ci1))  #<__main__.C1 object at 0x0000024C44A80C18>
print(repr(ci1)) #<__main__.C1 object at 0x0000024C44A80C18>
print(ci2)       #C2 class str
print(str(ci2))  #C2 class str
print(repr(ci2)) #<__main__.C2 object at 0x0000024C44AE12E8>
print(ci3)       #C3 class repr
print(str(ci3))  #C3 class repr
print(repr(ci3)) #C3 class repr
print(ci4)       #C4 class str 
print(str(ci4))  #C4 class str 
print(repr(ci4)) #C4 class repr
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top