metodo example __repr__ python magic-methods repr

python - example - Diferencia entre__str__ y__repr__?



metodo__ repr__ (21)

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

__str__ (leído como "cadena dunder (doble guión bajo)") y __repr__ (leído como "dunder-repper" (para "representación")) son métodos especiales que devuelven cadenas basadas en el estado del objeto.

__repr__ proporciona un comportamiento de copia de seguridad si __str__ falta.

Por lo tanto, primero debe escribir un __repr__ que le permita reinstituir un objeto equivalente de la cadena que devuelve, por ejemplo, utilizando eval o escribiéndolo en carácter por carácter en un shell de Python.

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

__str__

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

__repr__

El método __repr__ es llamado por la función incorporada repr y es lo que se refleja 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 incorporada 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 se imprime con repr , debería poder crear un objeto equivalente. Pero esta no es la implementación por defecto.

Implementación predeterminada de __repr__

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

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

Esto significa que, de forma predeterminada, imprimirá el módulo del que proviene el 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 manera de determinar cómo se puede crear con precisión una representación canónica de una instancia determinada, y es mejor que nada, al menos nos dice cómo podemos identificarla de forma única en la memoria.

¿Cómo puede __repr__ ser útil?

Veamos lo útil que puede ser, utilizando el shell de Python y los objetos de datetime y 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 de fecha y hora equivalente. Esto es creado por el datetime __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 es implementado por __str__ de datetime:

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

Es una cuestión simple recrear el objeto que perdimos porque no lo asignamos a una variable copiando y pegando desde la salida de __repr__ , y luego imprimiéndolo, y obtenemos el mismo resultado legible para el ser humano 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 se desarrolle, querrá poder reproducir objetos en el mismo estado, si es posible. Esto, por ejemplo, es cómo 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 = ", ".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

Si desea que su objeto tenga una representación legible más humana, puede implementar __str__ continuación. Así es como el objeto datetime ( fuente de Python ) implementa __str__ , lo que hace fácilmente porque ya tiene una función para mostrarlo en formato ISO:

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

Establecer __repr__ = __str__ ?

Esta es una crítica de otra respuesta que sugiere establecer __repr__ = __str__ .

Establecer __repr__ = __str__ es una tontería - __repr__ es una alternativa para __str__ y __repr__ , escrito para uso de los desarrolladores en la depuración, debe escribirse antes de escribir un __str__ .

Necesita un __str__ solo cuando necesita una representación textual del objeto.

Conclusión

Defina __repr__ para los objetos que escribe para que usted y otros desarrolladores tengan un ejemplo reproducible cuando lo usen a medida que lo desarrolla. Defina __str__ cuando necesite una representación humana de la misma.

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


En resumen, el objetivo de __repr__ es no ser ambiguo y __str__ debe ser 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 (comillas inversas). A veces es útil poder acceder a esta operación como una función ordinaria. Para muchos tipos, esta función intenta devolver una cadena que produciría un objeto con el mismo valor cuando se pasa a eval() , de lo contrario, la representación es una cadena entre paréntesis angulares que contiene el nombre del tipo de objeto. con información adicional que a menudo incluye el nombre y la dirección del objeto. Una clase puede controlar lo que esta función devuelve para sus instancias definiendo un __repr__() .

Aquí está la documentación para str:

str(object='''')

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


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


A menos que actúe específicamente para garantizar que 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 ve, no hay diferencia, y no hay información más allá de la clase y la id del 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 invalida __repr__ , TAMBIÉN se usa para __str__ , pero no al revés.

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

Por lo tanto, mi consejo: concéntrese en hacer __str__ razonablemente legible para el ser humano, y __repr__ más inequívoco que pueda, incluso si eso interfiere con el objetivo inalcanzable de hacer que __repr__ devuelva el valor aceptable como entrada para __eval__ !


Aparte 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 el objeto con la declaración de impresión.

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

4) __str__() de contenedores, cuando se invoca ejecutará el __repr__() de sus elementos contenidos.

5) str() llamado dentro de __str__() potencialmente podría recuperarse sin un caso base, y 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 ...


Comprenda __str__ y __repr__ intuitiva y permanentemente, distingalas en absoluto.

__str__ devuelve la cadena disfrazada del cuerpo de un objeto dado para que sea legible de los ojos
__repr__ devuelve el cuerpo de carne real de un objeto determinado (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 hacer operaciones aritméticas en __repr__ resultados 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 terrenos concretos para explorar más respuestas.


Con toda honestidad, eval(repr(obj)) nunca se usa. Si se encuentra usándolo, debe dejar de hacerlo, porque eval es peligroso y las cadenas son una manera muy ineficiente de serializar sus objetos (use pickle lugar).

Por lo tanto, recomendaría establecer __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). Una repr real probablemente no será muy útil como resultado de la print [your, objects] .

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


Desde http://pyref.infogami.com/__str__ por effbot:

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


En la página 358 del libro Python scripting para computational science de Hans Petter Langtangen, se establece claramente que

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

Por eso, prefiero entenderlos como

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

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

Un ejemplo pequeño pero bueno también se da 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''


En una palabra:

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


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

Por esta razón, si tengo un __str__ 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))


Mi regla de oro: __repr__ es para desarrolladores, __str__ es para clientes.


Mucho más claro desde el blog

Str es como toString. creado para que pueda imprimir la reproducción de datos es como serializar, o encurtir. ¿Cómo puedo recrear este objeto si necesito hacerlo 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))


Para hacerlo mas simple:

__str__ se usa para mostrar una representación en cadena de su objeto para que otros puedan leerlo fácilmente .

__repr__ se utiliza para mostrar una representación de cadena del objeto.

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

Entonces podemos crear una clase de fracciones 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)


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

  • Objetivo de __str__ : legible por humanos
  • Objetivo de __repr__ : no ambiguo, posiblemente legible por máquina a través de eval

Desafortunadamente, esta diferenciación es defectuosa, porque el REPL de Python y también el IPython utilizan __repr__ para imprimir objetos en una consola REPL (consulte las preguntas relacionadas con Python e IPython ). Por lo tanto, los proyectos dirigidos al trabajo de la consola interactiva (p. Ej., Numpy o Pandas) han comenzado a ignorar las reglas anteriores y proporcionar una implementación __repr__ legible para el __repr__ .


__repr__ se usa en todas partes, excepto por print y str cuando se define un __str__


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 salida para el usuario final

repr ():

  • Necesita código que reproduzca el objeto.
  • genera salida para desarrollador

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

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

p.ej

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


Alex resumió bien pero, sorprendentemente, era demasiado breve.

Primero, permítame reiterar los puntos principales en el post de Alex :

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

La implementación por defecto 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__)

hubiera sido demasiado peligroso (por ejemplo, demasiado fácil para obtener una recursión infinita si los objetos se hacen referencia entre sí). Así que Python se va fuera. Tenga en cuenta que hay un valor predeterminado que es verdadero: si __repr__ está definido y __str__ no, el objeto se comportará como si __str__=__repr__ .

Esto significa, en términos simples: casi todos los objetos que implementa deben tener un __repr__ funcional que se pueda utilizar para comprender el objeto. Implementar __str__ es opcional: haga eso si necesita una funcionalidad de "impresión bonita" (por ejemplo, utilizada por un generador de informes).

El objetivo de __repr__ es ser inequívoco

Déjame salir y decirlo: no creo en los depuradores. Realmente no sé cómo usar ningún depurador, y nunca he usado uno en serio. Además, creo que la gran falla de los depuradores es su naturaleza básica: la mayoría de los fallos que depuro ocurrieron hace mucho tiempo, en una galaxia 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 de "quita y olvida". Python facilita el registro: tal vez con algunos envoltorios 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: asegúrate de que cada objeto que implementes tenga una reproducción útil, por lo que un código como ese puede funcionar. Esta es la razón por la que surge la cosa "eval": 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 forma difusa, hazlo. Si no, asegúrate de tener suficiente información sobre c todos modos. Usualmente uso un formato similar a eval: "MyClass(this=%r,that=%r)" % (self.this,self.that) . No significa que realmente pueda construir MyClass, o que esos sean los argumentos correctos del constructor, pero es una forma útil de expresar "esto es todo lo que necesita saber sobre esta instancia".

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

El objetivo de __str__ es ser legible.

Específicamente, no se pretende que sea inequívoco: observe que str(3)==str("3") . Del mismo modo, si implementa una abstracción de IP, tener el str de él como 192.168.1.1 está bien. Cuando se implementa una abstracción de fecha / hora, el str puede ser "2010/4/12 15:35:22", etc. El objetivo es representarlo de una manera en que un usuario, no un programador, quiera leerlo. Corte dígitos inútiles, simule ser otra clase: mientras sea compatible con la legibilidad, es una mejora.

Contenedor __str__ utiliza objetos contenidos __repr__

Esto parece sorprendente, ¿no? Es un poco, pero lo legible sería.

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

¿ser? No muy. Específicamente, a las cadenas de un contenedor les resultaría demasiado fácil alterar su representación de cadena. Ante la ambigüedad, recuerda, Python resiste la tentación de adivinar. Si desea el comportamiento anterior cuando está imprimiendo una lista, simplemente

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

(Es probable que también puedas averiguar qué hacer con los diccionarios.

Resumen

Implementar __repr__ para cualquier clase que implementes. Esto debería ser una segunda naturaleza. Implemente __str__ si cree que sería útil tener una versión de cadena que cometa errores en el sentido de una mayor legibilidad en favor de una mayor ambigüedad.


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

Del libro: Fluent Python


>>> print(decimal.Decimal(23) / decimal.Decimal("1.05")) 21.90476190476190476190476190 >>> decimal.Decimal(23) / decimal.Decimal("1.05") Decimal(''21.90476190476190476190476190'')

Cuando se llama a 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 un decimal. Salida decimal: esta salida se encuentra en una forma representativa que se puede lograr con __repr __ (). Todos los objetos de Python tienen dos formas de salida. La forma de la cuerda está diseñada para ser legible por humanos. La forma representativa está diseñada para producir una salida que, si se alimenta a un intérprete de Python, (cuando sea posible), reproduzca el objeto representado