¿Cuál es la diferencia entre __str__
y __repr__
en Python?
fuente
¿Cuál es la diferencia entre __str__
y __repr__
en Python?
Alex resumió bien pero, sorprendentemente, fue demasiado sucinto.
Primero, permítanme reiterar los puntos principales en la publicación de Alex :
__repr__
el objetivo es no ser ambiguo__str__
el objetivo es ser legible__str__
utiliza objetos contenidos '__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 el __repr__
cual 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 así fuera __str__=__repr__
.
Esto significa, en términos simples: casi todos los objetos que implementes deben tener una función __repr__
que sea útil para comprender el objeto. La implementación __str__
es opcional: hágalo 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 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: la mayoría de las fallas que depuro ocurrieron hace mucho, 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 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 tiene que hacer el último paso: asegúrese de que cada objeto que implemente 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 cuestión "evaluar": si tiene suficiente información eval(repr(c))==c
, eso significa que sabe todo lo que hay que saber c
. Si eso es lo suficientemente fácil, al menos de manera difusa, hazlo. De lo contrario, asegúrese de tener suficiente información acerca de c
todos modos. Yo suelo usar una eval-como formato: "MyClass(this=%r,that=%r)" % (self.this,self.that)
. No significa que pueda construir MyClass, o que esos son los argumentos de constructor correctos, pero es una forma útil para expresar "esto es todo lo que necesita saber sobre esta instancia".
Nota: Utilicé %r
arriba, no %s
. Siempre desea utilizar repr()
[o %r
formatear caracteres, de manera equivalente] dentro de la __repr__
implementación, o está anulando el objetivo de repr. Desea poder diferenciar MyClass(3)
y MyClass("3")
.
El objetivo de __str__
es ser legible
Específicamente, no está destinado a ser inequívoco; tenga en cuenta eso 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 una manera que un usuario, no un programador, quiera leerlo. Corta los dígitos inútiles, finge ser otra clase, siempre y cuando sea compatible con la legibilidad, es una mejora.
El contenedor __str__
utiliza objetos contenidos '__repr__
Esto parece sorprendente, ¿no? Es un poco, pero ¿qué tan legible sería si usara sus __str__
?
[moshe is, 3, hello
world, this is a list, oh I don't know, containing just 4 elements]
No muy. Específicamente, las cadenas en un contenedor encontrarían demasiado fácil alterar su representación de cadena. Ante la ambigüedad, recuerde, Python resiste la tentación de adivinar. Si desea el comportamiento anterior cuando imprime una lista, solo
print "[" + ", ".join(l) + "]"
(probablemente también pueda averiguar qué hacer con los diccionarios.
Resumen
Implemente __repr__
para cualquier clase que implemente. Esto debería ser una segunda naturaleza. Implemente __str__
si cree que sería útil tener una versión de cadena que tenga errores de legibilidad.
__repr__
era lo que necesitaba para depurar. Gracias por tu ayuda.Mi regla de oro:
__repr__
es para desarrolladores,__str__
es para clientes.fuente
__str__
para que los desarrolladores normales tengan un objeto legible. Por otro lado,__repr__
es para los propios desarrolladores de SDK.A menos que actúes específicamente para asegurarte de lo contrario, la mayoría de las clases no tienen resultados útiles para:
Como puede ver, no hay diferencia y no hay información más allá de la clase y el objeto
id
. Si solo anula uno de los dos ...:como ve, si anula
__repr__
, TAMBIÉN se usa__str__
, pero no al revés.Otros datos cruciales que debe saber:
__str__
en un contenedor incorporado, se 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 los__repr__
objetos sean una cadena queeval
pueda usar para construir un objeto igual (es demasiado difícil, Y no saber cómo se importó realmente el módulo relevante lo hace realmente completamente imposible).Por lo tanto, mi consejo: ¡enfóquese en hacer
__str__
razonablemente legible para los humanos, y lo__repr__
más inequívoco posible, incluso si eso interfiere con el objetivo difuso inalcanzable de hacer que__repr__
el valor devuelto sea aceptable como entrada para__eval__
!fuente
eval(repr(foo))
evalúa como un objeto igual afoo
. Tienes razón en que no va a trabajar fuera de mis casos de prueba, ya que no sé cómo se importa el módulo, pero esto por lo menos asegura que funciona en algunos contexto predecible. Creo que esta es una buena forma de evaluar si el resultado de__repr__
es suficientemente explícito. Hacer esto en una prueba unitaria también ayuda a garantizar que se__repr__
sigan los cambios en la clase.eval(repr(spam)) == spam
(al menos en el contexto correcto), oeval(repr(spam))
levante aSyntaxError
. De esa manera evitas la confusión. (Y eso es casi cierto para los builtins y la mayoría de los stdlib, excepto, por ejemplo, listas recursivas, dondea=[]; a.append(a); print(eval(repr(a)))
te da[[Ellipses]]
...) Por supuesto, no hago eso para usarlo realmenteeval(repr(spam))
, excepto como un control de cordura en pruebas unitarias ... pero yo a veces copie y peguerepr(spam)
en una sesión interactiva.__str__
para cada elemento en lugar de__repr__
? Me parece completamente incorrecto, ya que implementé un legible__str__
en mi objeto y cuando es parte de una lista, veo el más feo en su__repr__
lugar.eval(repr(x))
falla incluso para los tipos incorporados:class A(str, Enum): X = 'x'
aumentará SyntaxErroreval(repr(A.X))
. Es triste, pero comprensible. Por cierto, eneval(str(A.X))
realidad funciona, pero por supuesto solo siclass A
está dentro del alcance, por lo que probablemente no sea muy útil.str
elemento de uso de contenedorrepr
porque[1, 2, 3]
! =["1", "2, 3"]
.__repr__
: la representación del objeto de Python generalmente eval lo convertirá de nuevo a ese objeto__str__
: es lo que creas que es ese objeto en forma de textop.ej
fuente
Aquí hay un buen ejemplo:
Lea esta documentación para repr:
Aquí está la documentación para str:
fuente
__str__
(leído como "cadena dunder (doble subrayado)") 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 comportamiento de respaldo si__str__
falta.Por lo tanto, primero debe escribir un
__repr__
que le permita reinstalar un objeto equivalente de la cadena que devuelve, por ejemplo, utilizandoeval
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
ostr
, si__str__
se define un método, se llamará a ese método, de lo contrario,__repr__
se utilizará.__repr__
La
__repr__
función incorporada llama al métodorepr
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 sobre
repr
: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 de C Python ) algo como:Eso 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:
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
__repr__
ser útil?Veamos qué tan útil puede ser, usando el shell y los
datetime
objetos de Python . Primero necesitamos importar eldatetime
módulo:Si llamamos
datetime.now
al shell, veremos todo lo que necesitamos para recrear un objeto datetime equivalente. Esto es creado por la fecha y hora__repr__
:Si imprimimos un objeto de fecha y hora, vemos un buen formato legible por humanos (de hecho, ISO). Esto se implementa por datetime
__str__
:Es simple recrear el objeto que perdimos porque no lo asignamos a una variable copiando y pegando desde la
__repr__
salida, y luego imprimiéndolo, y lo obtenemos en la misma salida legible por humanos que el otro objeto:¿Cómo los implemento?
A medida que desarrolles, querrás poder reproducir objetos en el mismo estado, si es posible. Así, por ejemplo, es cómo define el objeto datetime
__repr__
( fuente de Python ). Es bastante complejo, debido a todos los atributos necesarios para reproducir dicho objeto:Si desea que su objeto tenga una representación más legible para el ser humano, puede implementarlo a
__str__
continuación. Así es como se implementa el objeto datetime ( fuente de Python )__str__
, lo que hace fácilmente porque ya tiene una función para mostrarlo en formato ISO:Conjunto
__repr__ = __str__
?Esta es una crítica de otra respuesta aquí que sugiere la configuración
__repr__ = __str__
.La configuración
__repr__ = __str__
es una tontería:__repr__
es una alternativa__str__
y__repr__
, escrita para el uso de los desarrolladores en la depuración, debe escribirse antes de escribir una__str__
.Necesita un
__str__
solo cuando necesita una representación textual del objeto.Conclusión
Defina los
__repr__
objetos que escribe para que usted y otros desarrolladores tengan un ejemplo reproducible cuando lo usen mientras desarrolla. Defina__str__
cuándo necesita una representación de cadena legible por humanos.fuente
type(obj).__qualname__
?En la página 358 del libro de secuencias de comandos Python para la ciencia computacional de Hans Petter Langtangen, se afirma claramente que
__repr__
objetivo es una representación de cadena completa del objeto;__str__
es devolver una buena cadena para imprimir.Entonces, prefiero entenderlos como
desde el punto de vista del usuario, aunque este es un malentendido que hice al aprender Python.
Un pequeño pero buen ejemplo también se da en la misma página de la siguiente manera:
Ejemplo
fuente
repr
reproducir. Es mejor pensar en ello como representar.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
__str__
falte, imprima y cualquier función utilizandostr()
invocaciones__repr__()
de objeto.4)
__str__()
de contenedores, cuando se invoca ejecutará el__repr__()
método de sus elementos contenidos.5)
str()
llamado dentro__str__()
podría recurrir potencialmente sin un caso base y error en la profundidad máxima de recursión.6)
__repr__()
puede llamar,repr()
lo que intentará evitar la recursión infinita automáticamente, reemplazando un objeto ya representado por...
.fuente
Para hacerlo mas simple:
__str__
se utiliza para mostrar una representación de cadena de su objeto para que se lea fácilmente .__repr__
se utiliza para mostrar una representación de cadena del objeto.Digamos que quiero crear una
Fraction
clase donde la representación de cadena de una fracción sea '(1/2)' y el objeto (clase Fraction) se represente como 'Fracción (1,2)'Entonces podemos crear una clase de fracción simple:
fuente
Con toda honestidad,
eval(repr(obj))
nunca se usa. Si te encuentras usándolo, debes detenerte, porqueeval
es peligroso, y las cadenas son una forma muy ineficiente de serializar tus objetos (en supickle
lugar, úsalo).Por lo tanto, recomendaría la configuración
__repr__ = __str__
. La razón es questr(list)
recurrerepr
a los elementos (considero que este es uno de los mayores defectos de diseño de Python que no fue abordado por Python 3). Un realrepr
probablemente no será muy útil como salida deprint [your, objects]
.Para calificar esto, en mi experiencia, el caso de uso más útil de la
repr
función 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 estáeval
sucediendo aquí.fuente
eval(repr(obj))
es una prueba de cordura y una regla general: si esto recrea el objeto original correctamente, entonces tiene una__repr__
implementación decente . No se pretende que serialices objetos de esta manera.eval
No es inherentemente peligroso. No es más peligrosa queunlink
,open
o escribir en archivos. ¿Deberíamos dejar de escribir en archivos porque tal vez un ataque malicioso podría usar una ruta de archivo arbitraria para poner contenido dentro? Todo es peligroso si lo usan tontamente las personas tontas. La idiotez es peligrosa. Los efectos de Dunning-Kruger son peligrosos.eval
Es solo una función.De un Wiki de referencia de Python (no oficial) (copia de archivo) de effbot:
__str__
" calcula la representación de cadena" informal "de un objeto. Esto difiere de__repr__
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 " .fuente
__repr__
de ninguna manera se requiere para devolver una expresión Python vaild.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 ():
repr ():
fuente
Un aspecto que falta en otras respuestas. Es cierto que en general el patrón es:
__str__
: legible por humanos__repr__
: inequívoco, posiblemente legible por máquina a través deeval
Desafortunadamente, esta diferenciación es defectuosa, ya que Python REPL y también IPython usan
__repr__
para imprimir objetos en una consola REPL (ver preguntas relacionadas para Python e 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, en su lugar, proporcionan una__repr__
implementación legible para los humanos .fuente
Del libro Fluent Python :
fuente
Las excelentes respuestas 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 lo más útil posible para los desarrolladores. Teniendo en cuenta eso, encuentro que la implementación predeterminada de a__repr__
menudo no logra este objetivo porque omite información útil para los desarrolladores.Por esta razón, si tengo una idea bastante simple
__str__
, generalmente trato de obtener lo mejor de ambos mundos con algo como:fuente
Python favorece la ambigüedad sobre la legibilidad , la
__str__
llamada de untuple
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 una informal, es inequívoca y más robusta contra los errores.fuente
__repr__
cuando (__str__
) no está definido! Entonces te equivocas.En una palabra:
fuente
Cuando
print()
se llama en el resultado deldecimal.Decimal(23) / decimal.Decimal("1.05")
número bruto se imprime; esta salida está en forma de cadena que se puede lograr con__str__()
. Si simplemente ingresamos la expresión, obtenemos unadecimal.Decimal
salida; 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, reproducirían (cuando sea posible) el objeto representado.fuente
__str__
se puede invocar en un objeto llamandostr(obj)
y debe devolver una cadena legible por humanos.__repr__
se puede invocar en un objeto llamandorepr(obj)
y debe devolver un objeto interno (campos / atributos del objeto)Este ejemplo puede ayudar:
fuente
Comprender
__str__
y__repr__
distinguirlos intuitiva y permanentemente.__str__
devuelve el cuerpo encubierto de una cadena de un objeto dado para que los ojos__repr__
puedan leerlo devuelve el cuerpo real de carne de un objeto dado (regresa a sí mismo) para que no se identifique la ambigüedad.Véalo en un ejemplo
En cuanto a
__repr__
Podemos hacer operaciones aritméticas en
__repr__
resultados convenientemente.si aplica la operación en
__str__
No devuelve nada más que error.
Otro ejemplo.
Espero que esto te ayude a construir bases concretas para explorar más respuestas.
fuente
__str__
debe devolver un objeto de cadena mientras que__repr__
puede devolver cualquier expresión de Python.__str__
falta la implementación, la__repr__
función se utiliza como reserva. No hay respaldo si__repr__
falta la implementación de la función.__repr__
función devuelve una representación de cadena del objeto, podemos omitir la implementación de la__str__
función.Fuente: https://www.journaldev.com/22460/python-str-repr-functions
fuente
__repr__
se usa en todas partes, excepto porprint
ystr
métodos (cuando__str__
se define a)fuente