Respuestas:
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.
__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:
>>> 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 eval
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__
!
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.
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.
__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á SyntaxError eval(repr(A.X))
. Es triste, pero comprensible. Por cierto, en eval(str(A.X))
realidad funciona, pero por supuesto solo si class A
está dentro del alcance, por lo que probablemente no sea muy útil.
str
elemento de uso de contenedor repr
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 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
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 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,''
.
¿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 eval
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
o 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 repr
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
:
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.
__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.
__repr__
ser útil?Veamos qué tan útil puede ser, usando el shell y los datetime
objetos de Python . Primero necesitamos importar el datetime
módulo:
import datetime
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__
:
>>> 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
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=' ')
__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.
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.
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:
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'
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 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 ...
.
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:
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)
Con toda honestidad, eval(repr(obj))
nunca se usa. Si te encuentras usándolo, debes detenerte, porque eval
es peligroso, y las cadenas son una forma muy ineficiente de serializar tus objetos (en su pickle
lugar, úsalo).
Por lo tanto, recomendaría la configuración __repr__ = __str__
. La razón es que str(list)
recurre repr
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 real repr
probablemente 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 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í.
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 que unlink
, 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 " .
__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 ():
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 .
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.
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))
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 tuple
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.
__repr__
cuando ( __str__
) no está definido! Entonces te equivocas.
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'
>>> 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.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.
__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
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.
__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