Pregunta Diferencia entre __str__ y __repr__?


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


2107
2017-09-17 04:27


origen


Respuestas:


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

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 sería, pero sí)
  • __repr__ el objetivo es ser inequívoco
  • __str__ el objetivo es ser legible
  • Contenedor __str__ usa 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 __repr__ que actuaría así:

return "%s(%r)" % (self.__class__, self.__dict__)

habría sido demasiado peligroso (por ejemplo, demasiado fácil acceder a recursividad infinita si los objetos se referencian entre sí). Entonces Python termina. Tenga en cuenta que hay un valor predeterminado que es verdadero: si __repr__ está definido, y __str__ no es así, el objeto se comportará como si __str__=__repr__.

Esto significa, en términos simples: casi todos los objetos que implementa deben tener un funcional __repr__ eso es útil para entender el objeto. Implementar __str__ es opcional: hazlo si necesitas 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 lo he usado en serio. Además, creo que la gran falla en los depuradores es su naturaleza básica: la mayoría de los fallos que depuré sucedieron hace mucho tiempo, en una galaxia muy distante. Esto significa que sí creo, con fervor religioso, en la explotación maderera. La registración es el alma de cualquier sistema de servidor digno de "olvidar y olvidar". Python hace que sea fácil iniciar sesión: con algunas envolturas específicas para el 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 implemente tenga una respuesta útil, de modo que un código como ese pueda funcionar. Esta es la razón por la que surge la pregunta "eval": si tienes suficiente información, eval(repr(c))==c, eso significa que sabes todo lo que hay que saber sobre c. Si eso es bastante fácil, al menos de una manera difusa, hazlo. Si no, asegúrese de tener suficiente información acerca de c de todas formas. Usualmente uso un formato de tipo eval: "MyClass(this=%r,that=%r)" % (self.this,self.that). No significa que realmente pueda construir MyClass, o que esos sean los argumentos constructor correctos, pero es una forma útil de expresar "esto es todo lo que necesita saber sobre esta instancia".

Nota: utilicé %r arriba, no %s. Siempre quieres usar repr() [o %r personaje de formato, equivalentemente] dentro __repr__ implementación, o está derrotando el objetivo de repr. Quieres ser capaz de 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 que str(3)==str("3"). Del mismo modo, si implementa una abstracción de IP, tener la estructura parece ser 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. Corte los dígitos inútiles, pretenda ser de otra clase, siempre que sea compatible con la legibilidad, es una mejora.

Contenedor __str__ usa objetos contenidos __repr__

Esto parece sorprendente, ¿no? Es un poco, pero qué tan legible

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

¿ser? No muy. Específicamente, las cadenas en un contenedor encontrarán demasiado fácil alterar su representación de cadena. En vista de 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) + "]"

(Probablemente también pueda averiguar qué hacer con los diccionarios.

Resumen

Implementar __repr__ para cualquier clase que implemente. Esto debería ser una segunda naturaleza. Implementar __str__ si crees que sería útil tener una versión de cadena que se equivoca al lado de una mayor legibilidad a favor de una mayor ambigüedad.


2171
2018-04-13 00:56



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


369
2017-09-17 11:35



A menos que actúe específicamente para garantizar 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 el objeto id. Si solo anulas 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 ves, si anulas __repr__, eso también se usa para __str__, pero no al revés

Otras cositas cruciales para saber: __str__ en un contenedor incorporado utiliza el __repr__, No la __str__, para los artículos 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 el __repr__ de objetos sea una cadena que eval puede usarse para construir un objeto igual (es demasiado difícil, Y al no saber cómo se importó realmente el módulo relevante, hace que sea realmente imposible).

Entonces, mi consejo: concéntrese en hacer __str__ razonablemente humanamente legible, y __repr__ tan inequívoco como sea posible, incluso si eso interfiere con el objetivo difuso inalcanzable de hacer __repr__El valor devuelto es aceptable como entrada a __eval__!


319
2017-09-17 04:49



__repr__: representación del objeto python generalmente eval lo convertirá nuevamente 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

143
2017-09-17 04:35



En resumen, el objetivo de __repr__ es ser inequívoco y __str__ es para 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 generado por las conversiones (inversa   citas). A veces es útil poder acceder a esta operación como   una función ordinaria. Para muchos tipos, esta función hace un intento   para devolver una cadena que produciría un objeto con el mismo valor cuando   pasó a eval(), de lo contrario, la representación es una cadena encerrada en   corchetes angulares que contienen el nombre del tipo del objeto   junto con información adicional que a menudo incluye el nombre y   dirección del objeto. Una clase puede controlar el retorno de esta función   para sus instancias mediante la definición de una __repr__() método.

Aquí está la documentación para str:

str(object='')

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


114
2017-10-25 18:38



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

__str__ (leer como "dunder (double-underscore) string") y __repr__ (leer como "dunder-repper" (para "representación")) son ambos métodos especiales que devuelven cadenas basadas en el estado del objeto.

__repr__ proporciona un comportamiento de respaldo si __str__ Está perdido.

Entonces uno debería primero escribir un __repr__ que le permite reinstalar un objeto equivalente de la cadena que devuelve, p. utilizando eval o escribiéndolo en carácter por personaje en un shell de Python.

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

__str__

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

__repr__

los __repr__ método es llamado por la función incorporada repr y es lo que se repite en el shell de python cuando evalúa una expresión que devuelve un objeto.

Dado que proporciona una copia de seguridad para __str__, si solo puedes escribir uno, comienza con __repr__

Aquí está la ayuda integrada 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 está impreso repr, deberías poder crear un objeto equivalente. Pero esta no es la implementación predeterminada.

Implementación predeterminada de __repr__

El objeto predeterminado __repr__ es (C fuente de 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 es 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 dada, y es mejor que nada, al menos nos dice cómo podríamos identificarlo de manera única en la memoria.

¿Cómo puede __repr__ ¿sé útil?

Veamos lo útil que puede ser, usando el shell Python y datetime objetos. Primero tenemos que importar el datetime módulo:

import datetime

Si llamamos datetime.now en el 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 datetime, vemos un buen formato legible por humanos (de hecho, ISO). Esto se implementa por fecha y hora __str__:

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

Es una simple cuestión de recrear el objeto que perdimos porque no lo asignamos a una variable copiando y pegando desde el __repr__ salida, y luego imprimirlo, y lo conseguimos en la misma salida legible para 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. Esto, 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 = ", ".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__ siguiente. Así es como el objeto datetime (Fuente de Python) implementa __str__, lo cual 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 establecer __repr__ = __str__.

Ajuste __repr__ = __str__ es tonto - __repr__ es un respaldo para __str__ y un __repr__, escrito para el uso de los desarrolladores en la depuración, debe escribirse antes de escribir un __str__.

Tu necesitas un __str__ solo cuando necesitas una representación textual del objeto.

Conclusión

Definir __repr__ para objetos que escribes para que tú y otros desarrolladores tengan un ejemplo reproducible cuando lo usas a medida que te desarrollas. Definir __str__ cuando necesita una representación legible de cadena humana de la misma.


84
2018-01-25 02:01



Además de todas las respuestas dadas, quisiera agregar algunos puntos:

1) __repr__() se invoca cuando simplemente escribes el nombre del objeto en la consola de python interactiva y presionas enter.

2) __str__() se invoca cuando usa object con print statement.

3) En caso, si __str__ falta, luego imprimir y usar cualquier función str() invoca __repr__() de objeto

4) __str__() de contenedores, cuando se invoque se ejecutará __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() que intentará evitar la recursión infinita automáticamente, reemplazando un objeto ya representado con ....


12
2017-09-08 03:27



Con toda honestidad, eval(repr(obj)) nunca se usa Si te encuentras usándolo, debes parar, porque eval es peligroso, y las cadenas son una forma muy ineficiente de serializar sus objetos (uso pickle en lugar).

Por lo tanto, recomendaría establecer __repr__ = __str__. El motivo es que str(list) llamadas repr en los elementos (considero que este es uno de los mayores defectos de diseño de Python que Python 3 no abordó). Un real repr probablemente no será muy útil ya que la salida de print [your, objects].

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


11
2017-11-15 10:39



Para hacerlo mas simple:

__str__ se usa para mostrar una representación de cadena de su objeto para ser leído fácilmente por otros.

__repr__ se usa para mostrar una representación de cadena de el objeto.

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

Entonces, podemos crear una clase simple de fracciones:

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)

10
2018-01-12 02:53



En la página 358 del libro Python scripting para ciencia computacional por Hans Petter Langtangen, establece claramente que

  • los __repr__apunta a una representación de cadena completa del objeto;
  • los __str__ es devolver una cadena muy bien para imprimir.

Entonces, prefiero entenderlos como

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

desde el punto de vista del usuario aunque esto es un malentendido que hice al aprender Python.

Un pequeño pero bueno 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'

10
2018-05-21 16:34



De 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: en su lugar, se puede usar una representación más conveniente o concisa ".


9
2017-09-17 04:28