Python __str__ y listas

107

En Java, si llamo a List.toString (), llamará automáticamente al método toString () en cada objeto dentro de la Lista. Por ejemplo, si mi lista contiene objetos o1, o2 y o3, list.toString () se vería así:

"[" + o1.toString() + ", " + o2.toString() + ", " + o3.toString() + "]"

¿Hay alguna forma de obtener un comportamiento similar en Python? Implementé un método __str __ () en mi clase, pero cuando imprimo una lista de objetos, uso:

print 'my list is %s'%(list)

se parece a esto:

[<__main__.cell instance at 0x2a955e95f0>, <__main__.cell instance at 0x2a955e9638>, <__main__.cell instance at 0x2a955e9680>]

¿Cómo puedo hacer que Python llame a mi __str__ automáticamente para cada elemento dentro de la lista (o dict para el caso)?

benhsu
fuente
Solo como referencia, hay PEP 3140: "str (contenedor) debe llamar a str (elemento), no repr (elemento)" , que fue rechazado.
Alexey

Respuestas:

133

Llamar a una cadena en una lista de Python llama al __repr__método en cada elemento dentro. Para algunos artículos, __str__y __repr__son los mismos. Si desea ese comportamiento, haga:

def __str__(self):
    ...
def __repr__(self):
    return self.__str__()
David Berger
fuente
7
Identificarse __str__con __repr__generalmente no está de acuerdo con el modelo de datos de Python , por lo que la solución de comprensión de listas propuesta por @ daniel-lew es más pitónica.
Ioannis Filippidis
2
Sin discusión. Respondí la pregunta tal como se hizo, que a menudo es la forma en que un recién llegado a Python quiere pensar en el problema, pero eso no significa que sea la mejor manera de responder.
David Berger
1
Python debe ser coherente con su propio modelo de datos y hacer lo mismo con todas las primitivas y agregados.
Terrence Brannon
2
Creo que el comportamiento predeterminado para las listas de Python es simplemente incorrecto. Esperaría que se str()devolviera en una lista str()para cada uno de los elementos individuales dentro.
SuperGeo
21

Puede usar una lista de comprensión para generar una nueva lista con cada elemento str () 'd automáticamente:

print([str(item) for item in mylist])
Dan Lew
fuente
6
O simplemente print(map(str, mylist)), es un poco más corto
anula
4
Un problema con esto es si el elemento de mi lista también podría ser una lista
Breandán Dalton
7

Dos cosas fáciles que puede hacer, usar la mapfunción o usar una comprensión.

Pero eso le da una lista de cadenas, no una cadena. Así que también tienes que unir los hilos.

s= ",".join( map( str, myList ) )

o

s= ",".join( [ str(element) for element in myList ] )

Entonces puede imprimir este objeto de cadena compuesta.

print 'my list is %s'%( s )
S.Lott
fuente
4

Dependiendo de para qué quieras usar esa salida, quizás __repr__sea ​​más apropiado:

import unittest

class A(object):
    def __init__(self, val):
        self.val = val

    def __repr__(self):
        return repr(self.val)

class Test(unittest.TestCase):
    def testMain(self):
        l = [A('a'), A('b')]
        self.assertEqual(repr(l), "['a', 'b']")

if __name__ == '__main__':
    unittest.main()
Horst Gutmann
fuente
3

Estoy de acuerdo con la respuesta anterior sobre el uso de listas por comprensión para hacer esto, pero ciertamente podría ocultar eso detrás de una función, si eso es lo que hace flotar su bote.

def is_list(value):
    if type(value) in (list, tuple): return True
    return False

def list_str(value):
    if not is_list(value): return str(value)
    return [list_str(v) for v in value]

Solo por diversión, hice list_str () recursivamente str () todo lo contenido en la lista.

Jeremy Cantrell
fuente
+1 Esto es útil cuando se implementa __str__y por __repr__separado
vincent gravitas
0

¿Algo como esto?

a = [1, 2 ,3]
[str(x) for x in a]
# ['1', '2', '3']
Qué está haciendo
fuente
0

Esto debería ser suficiente.

Al imprimir listas, así como otras clases de contenedor, los elementos contenidos se imprimirán usando __repr__, porque __repr__está destinado a ser utilizado para la representación de objetos internos. Si llamamos: help(object.__repr__)nos dirá:

Help on wrapper_descriptor:

__repr__(self, /)
    Return repr(self).

Y si lo llamamos help(repr), saldrá:

Help on built-in function repr in module builtins:

repr(obj, /)
    Return the canonical string representation of the object.

    For many object types, including most builtins, eval(repr(obj)) == obj.

Si __str__está implementado para un objeto y __repr__no, repr(obj)generará la salida predeterminada, al igual que print(obj)cuando no se implementa ninguno de estos.

Entonces, la única forma es implementarlo __repr__para su clase. Una posible forma de hacerlo es esta:

class C:           
    def __str__(self):
        return str(f"{self.__class__.__name__} class str ")

C.__repr__=C.__str__       
ci = C()    


print(ci)       #C class str 
print(str(ci))  #C class str 
print(repr(ci)) #C class str 
prosti
fuente
-3

La salida que está obteniendo es solo el nombre del módulo del objeto, el nombre de la clase y luego la dirección de memoria en hexadecimal, ya que la __repr__función no se anula.

__str__se usa para la representación de cadena de un objeto cuando se usa print. Pero como está imprimiendo una lista de objetos y no iterando sobre la lista para llamar al strmétodo para cada elemento, imprime la representación de los objetos.

Para __str__invocar la función, debe hacer algo como esto:

'my list is %s' % [str(x) for x in myList]

Si anula la __repr__función, puede usar el método de impresión como lo hacía antes:

class cell:
    def __init__(self, id):
        self.id = id
    def __str__(self):
        return str(self.id) # Or whatever
    def __repr__(self):
        return str(self) # function invoked when you try and print the whole list.

myList = [cell(1), cell(2), cell(3)]
'my list is %s' % myList

Entonces obtendrá " my list is [1, 2, 3]" como salida.

panagiwtis koligas
fuente
Esta respuesta parece responder a una pregunta completamente ajena. ¿Estás seguro de que lo pusiste en el lugar correcto?
Blckknght
sí Blckknght esta página que quería dar mi respuesta tenía un enlace a esta página desde otra publicación. así que me guió aquí y respondo aquí suponiendo que el tipo que hizo la pregunta vendrá aquí nuevamente y verá mi respuesta ... lo siento la incomodidad !!!
panagiwtis koligas
Si la otra pregunta se cerró como un duplicado de esta, entonces se supone que las respuestas existentes aquí ya deberían ocuparse de la otra pregunta. Si ese no es el caso, entonces debería marcar para reabrir esa pregunta, en lugar de publicar una respuesta incomprensible aquí, que es casi seguro que se eliminará. Ahora, es posible que tenga algo que decir que no esté cubierto por una de las otras 8 respuestas aquí, pero necesitaría que su respuesta tenga sentido en el contexto de esta página, ya que es esta pregunta la que está respondiendo. ¡Y no publique dos respuestas idénticas!
Blckknght
1
Oh, aunque ahora que lo miro de nuevo, parece que @charliebeckwith ha editado tu publicación para que sea completamente diferente, en lugar de publicar su propia respuesta, por alguna razón inexplicable. Normalmente no es así como funcionan las ediciones ...
Blckknght
@blckknght Comencé a editarlo antes de darme cuenta de lo errónea que estaba la respuesta. Completamente inexplicable por qué seguí adelante.
charliebeckwith