¿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 ctodos 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é %rarriba, no %s. Siempre desea utilizar repr()[o %rformatear 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 queevalpueda 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 Aestá dentro del alcance, por lo que probablemente no sea muy útil.strelemento de uso de contenedorreprporque[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, utilizandoevalo 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.formatostr, 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étodorepry 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
datetimeobjetos de Python . Primero necesitamos importar eldatetimemódulo:Si llamamos
datetime.nowal 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
reprreproducir. 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
Fractionclase 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, porqueevales peligroso, y las cadenas son una forma muy ineficiente de serializar tus objetos (en supicklelugar, úsalo).Por lo tanto, recomendaría la configuración
__repr__ = __str__. La razón es questr(list)recurrerepra los elementos (considero que este es uno de los mayores defectos de diseño de Python que no fue abordado por Python 3). Un realreprprobablemente no será muy útil como salida deprint [your, objects].Para calificar esto, en mi experiencia, el caso de uso más útil de la
reprfunció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áevalsucediendo 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.evalNo es inherentemente peligroso. No es más peligrosa queunlink,openo 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.evalEs 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 deevalDesafortunadamente, 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 untuplellama 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.Decimalsalida; 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 porprintystrmétodos (cuando__str__se define a)fuente