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 questr(object)
no siempre intenta devolver una cadena que sea aceptable paraeval()
; 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 deeval
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