¿Diferencia entre __str__ y __repr__?

Respuestas:

2724

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

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

  • La implementación predeterminada es inútil (es difícil pensar en una que no lo sea, pero sí)
  • __repr__ el objetivo es no ser ambiguo
  • __str__ el objetivo es ser legible
  • El contenedor __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.

moshez
fuente
154
Definitivamente no estoy de acuerdo con tu opinión de que la depuración no es el camino a seguir. Para el desarrollo, use un depurador (y / o registro), para producción use el registro. Con un depurador tiene una vista de todo lo que salió mal cuando ocurrió el problema. Puedes ver la imagen completa. A menos que esté registrando TODO, no puede obtener eso. Además, si está registrando todo lo que va a tener que pasar por toneladas de datos para obtener lo que desea.
Samuel
21
Gran respuesta (excepto la parte sobre no usar depuradores). Solo me gustaría agregar un enlace a estas otras preguntas y respuestas sobre str vs unicode en Python 3 que podría ser relevante para la discusión de las personas que han realizado el cambio.
ThatAintWorking
11
plus1 para depuradores son inútiles y no escalan ni un centavo. En su lugar, aumente el rendimiento de registro. Y sí, esta fue una publicación bien escrita. Resulta que __repr__era lo que necesitaba para depurar. Gracias por tu ayuda.
personal_cloud
77
Dejando de lado su locura de depurador, aprendí el% r y eso vale la pena de todos modos
Mickey Perlstein
77
en depurador vs no depurador: no obtenga opiniones tan arraigadas. En algunas aplicaciones, la depuración no es realista, generalmente cuando se trata de tiempo real o cuando su código solo se ejecuta de forma remota en una plataforma con poco acceso o sin consola. En la mayoría de los otros casos, será mucho más rápido detenerse en una excepción para investigar o establecer un punto de interrupción, ya que no tiene que pasar por miles de líneas de registro (lo que desordenará su disco y ralentizará la aplicación). Finalmente, no siempre es posible iniciar sesión, por ejemplo en dispositivos integrados, el depurador también es tu amigo.
RedGlyph
523

Mi regla de oro: __repr__es para desarrolladores, __str__es para clientes.

Ned Batchelder
fuente
2
Esto es cierto porque para obj = uuid.uuid1 (), obj .__ str __ () es "2d7fc7f0-7706-11e9-94ae-0242ac110002" y obj .__ repr __ () es "UUID ('2d7fc7f0-7706-11e9-94ae-0242ac ') ". ¡Los desarrolladores necesitan (valor + origen) mientras que los clientes necesitan un valor y no les importa cómo lo obtuvieron!
Naren Yellavula
1
Aquí el cliente no necesariamente significa usuario final. Es el cliente o usuario del objeto. Entonces, si se trata de un SDK, los desarrolladores del SDK lo usarán __str__para que los desarrolladores normales tengan un objeto legible. Por otro lado, __repr__es para los propios desarrolladores de SDK.
Shiplu Mokaddim
398

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 clase y el objeto id. 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 __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 que evalpueda 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__!

Alex Martelli
fuente
34
En mis pruebas unitarias siempre verifico que se eval(repr(foo))evalúa como un objeto igual a foo. 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.
Steven T. Snyder
44
Siempre trato de asegurarme de que eval(repr(spam)) == spam(al menos en el contexto correcto), o eval(repr(spam))levante a SyntaxError. 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, donde a=[]; a.append(a); print(eval(repr(a)))te da [[Ellipses]]...) Por supuesto, no hago eso para usarlo realmente eval(repr(spam)), excepto como un control de cordura en pruebas unitarias ... pero yo a veces copie y pegue repr(spam)en una sesión interactiva.
abarnert
¿Por qué no utilizarían contenedores (listas, tuplas) __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.
SuperGeo
Acabo de encontrar un error molesto relacionado con el hecho de que eval(repr(x))falla incluso para los tipos incorporados: class A(str, Enum): X = 'x'aumentará SyntaxError eval(repr(A.X)). Es triste, pero comprensible. Por cierto, en eval(str(A.X))realidad funciona, pero por supuesto solo si class Aestá dentro del alcance, por lo que probablemente no sea muy útil.
max
@SuperGeo Otras respuestas cubren esto: strelemento de uso de contenedor reprporque [1, 2, 3]! = ["1", "2, 3"].
mtraceur
163

__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 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
Andrew Clark
fuente
151

En resumen, el objetivo __repr__es ser inequívoco y __str__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 arrojaría un objeto con el mismo valor cuando se pasa eval(), de lo contrario, la representación es una cadena entre corchetes angulares que contiene el nombre del tipo de objeto junto con información adicional a menudo incluye el nombre y la dirección del objeto. Una clase puede controlar lo que devuelve esta función para sus instancias definiendo un __repr__()método.

Aquí está la documentación para str:

str(object='')

Devuelve una cadena que contiene una representación muy bien imprimible de un objeto. Para 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, ''.

bitoffdev
fuente
1
¿Cuál es el significado de una cadena imprimible aquí? ¿Puedes explicarlo por favor?
Vicrobot
115

¿Cuál es la diferencia entre __str__y __repr__en Python?

__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, utilizando evalo 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.formato str, 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étodo repry 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:

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 de C Python ) algo 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 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 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 el datetimemódulo:

import datetime

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

>>> 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 por datetime __str__:

>>> 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 __repr__salida, y luego imprimiéndolo, y lo obtenemos en 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 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:

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

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

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.

Aaron Hall
fuente
¿No debería ser algo así type(obj).__qualname__?
Solomon Ucko
@SolomonUcko sí, en Python 3, ese parece ser el caso: he estado buscando el código fuente donde se implementa esto y actualizaré mi respuesta con esa información cuando lo reúna.
Aaron Hall
33

En la página 358 del libro de secuencias de comandos Python para la ciencia computacional de Hans Petter Langtangen, se afirma claramente que

  • El __repr__objetivo es una representación de cadena completa del objeto;
  • El __str__es devolver una buena cadena para imprimir.

Entonces, 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 pequeño pero buen ejemplo 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'
Yong Yang
fuente
Está en la pág. # 351.
jiten
44
Es un poco engañoso referirse a reprreproducir. Es mejor pensar en ello como representar.
NelsonGon
31

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 utilizando str()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 ....

Mangu Singh Rajpurohit
fuente
14

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:

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)
Zer0
fuente
13

Con toda honestidad, eval(repr(obj))nunca se usa. Si te encuentras usándolo, debes detenerte, porque evales peligroso, y las cadenas son una forma muy ineficiente de serializar tus objetos (en su picklelugar, úsalo).

Por lo tanto, recomendaría la configuración __repr__ = __str__. La razón es que str(list)recurre repra los elementos (considero que este es uno de los mayores defectos de diseño de Python que no fue abordado por Python 3). Un real reprprobablemente 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 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í.

asmeurer
fuente
19
Creo que esto pierde el punto. El uso de 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.
jwg
77
evalNo es inherentemente peligroso. No es más peligrosa que unlink, 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.
Luis Masuelli
12

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

Casebash
fuente
3
__repr__de ninguna manera se requiere para devolver una expresión Python vaild.
Físico loco
10

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
Inconnu
fuente
8

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__: 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 .

bluenote10
fuente
7

Del libro Fluent Python :

Un requisito básico para un objeto Python es proporcionar representaciones de cadena utilizables de sí mismo, una utilizada para la depuración y el registro, otra para la presentación a los usuarios finales. Es por eso que los
métodos especiales __repr__y __str__existen en el modelo de datos.

Ijaz Ahmad Khan
fuente
5

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:

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

Una cosa importante a tener en cuenta es que el contenedor __str__utiliza 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 __str__llamada de un tuplellama 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.

zangw
fuente
¡Se usa __repr__ cuando ( __str__) no está definido! Entonces te equivocas.
jiten
4

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

Cuando print()se llama en el resultado del decimal.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 una decimal.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.

BattleDrum
fuente
4

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

__repr__se puede invocar en un objeto llamando repr(obj)y debe devolver un objeto interno (campos / atributos del objeto)

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
prosti
fuente
3

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

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'

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

Cálculo
fuente
3
  1. __str__debe devolver un objeto de cadena mientras que __repr__puede devolver cualquier expresión de Python.
  2. Si __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.
  3. Si la __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

Sampath
fuente
2

__repr__se usa en todas partes, excepto por printy strmétodos (cuando __str__se define a)

techkuz
fuente