Uso de la representación __str__ para imprimir objetos en contenedores en Python

He notado que cuando una instancia con un método __str__ sobrecargado se pasa a la función de print como un argumento, se imprime según lo previsto. Sin embargo, al pasar un contenedor que contiene una de esas instancias para print , utiliza el método __repr__ lugar. Es decir, print(x) muestra la representación de cadena correcta de x , e print(x, y) funciona correctamente, pero print([x]) o print((x, y)) imprime la representación __repr__ lugar.

En primer lugar, ¿por qué sucede esto? En segundo lugar, ¿hay una manera de corregir ese comportamiento de print en esta circunstancia?

El problema con el contenedor que usa el __str__ los objetos sería la ambigüedad total, ¿qué significaría, digamos, si la print L muestra [1, 2] ? L podría ser ['1, 2'] (una sola lista de elementos cuyo elemento de cadena contiene una coma) o cualquiera de las cuatro listas de 2 elementos (ya que cada elemento puede ser una cadena o int). La ambigüedad de tipo es común para la print por supuesto, pero la ambigüedad total para el número de elementos (ya que cada coma podría ser delimitación de elementos o parte de un elemento de cadena) fue la consideración decisiva.

No estoy seguro de por qué exactamente el método __str__ de una lista devuelve la __repr__ de los objetos contenidos dentro, así que lo busqué: [Python-3000] PEP: str (contenedor) debería llamar a str (item), no repr (item )

Argumentos a favor de ello:

– los contenedores se niegan a adivinar lo que el usuario quiere ver en str (contenedor) – alrededores, delimitadores, etc.

– repr (item) normalmente muestra información de tipo – apóstrofes alrededor de cadenas, nombres de clase, etc.

Así que es más claro qué es exactamente en la lista (ya que la representación de cadena del objeto podría tener comas, etc.). El comportamiento no va a desaparecer, según Guido “BDFL” van Rossum:

Permítanme ahorrarles a todos mucho tiempo y decir que me opongo a este cambio, y que creo que causaría demasiada perturbación para ser aceptada tan cerca de la versión beta.


Ahora, hay dos formas de resolver este problema para su código.

El primero es crear una list subclases e implementar su propio método __str__ .

 class StrList(list): def __str__(self): string = "[" for index, item in enumerate(self): string += str(item) if index != len(self)-1: string += ", " return string + "]" class myClass(object): def __str__(self): return "myClass" def __repr__(self): return object.__repr__(self) 

Y ahora para probarlo:

 >>> objects = [myClass() for _ in xrange(10)] >>> print objects [<__main__.myClass object at 0x02880DB0>, #... >>> objects = StrList(objects) >>> print objects [myClass, myClass, myClass #... >>> import random >>> sample = random.sample(objects, 4) >>> print sample [<__main__.myClass object at 0x02880F10>, ... 

Personalmente creo que esta es una idea terrible. Algunas funciones, como random.sample , como se demostró, en realidad devuelven objetos de list , incluso si se clasifican en sub-listas. Por lo tanto, si toma esta ruta puede haber muchas result = strList(function(mylist)) , que podrían ser ineficientes. También es una mala idea, ya que entonces probablemente tengas la mitad de tu código usando objetos de la list regular, ya que no los imprimes y la otra mitad usa objetos strList , lo que puede hacer que tu código se vuelva más confuso y más confuso. Aún así, la opción está ahí, y esta es la única manera de lograr que la función de print (o statement, para 2.x) se comporte de la manera que usted quiere.

La otra solución es simplemente escribir su propia función strList() que devuelve la cadena de la forma que desee:

 def strList(theList): string = "[" for index, item in enumerate(theList): string += str(item) if index != len(theList)-1: string += ", " return string + "]" >>> mylist = [myClass() for _ in xrange(10)] >>> print strList(mylist) [myClass, myClass, myClass #... 

Ambas soluciones requieren que refactorice el código existente, desafortunadamente, pero el comportamiento de str(container) está aquí para quedarse.

Porque cuando imprime la lista, generalmente está mirando desde la perspectiva del progtwigdor o la depuración. Si pretendía mostrar la lista, procesaría sus elementos de manera significativa, por lo que se utiliza repr.

Si desea que sus objetos se impriman mientras están en contenedores, defina repr

 class MyObject: def __str__(self): return "" __repr__ = __str__ 

Por supuesto, repr debería devolver una cadena que podría usarse como código para recrear su objeto, pero puede hacer lo que quiera.