Python __str__ e listas


107

Em Java, se eu chamar List.toString (), ele chamará automaticamente o método toString () em cada objeto dentro da Lista. Por exemplo, se minha lista contiver objetos o1, o2 e o3, list.toString () seria algo assim:

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

Existe uma maneira de obter um comportamento semelhante em Python? Implementei um método __str __ () em minha classe, mas quando imprimo uma lista de objetos, usando:

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

parece algo assim:

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

como posso fazer com que o python chame meu __str__ automaticamente para cada elemento dentro da lista (ou dict para esse assunto)?


Apenas para referência, existe o PEP 3140: "str (container) deve chamar str (item), não repr (item)" , que foi rejeitado.
Alexey

Respostas:


133

Chamar string em uma lista python chama o __repr__método em cada elemento interno. Para alguns itens, __str__e __repr__são iguais. Se você deseja esse comportamento, faça:

def __str__(self):
    ...
def __repr__(self):
    return self.__str__()

7
Identificar __str__com __repr__geralmente não concorda com o modelo de dados Python , então a solução de compreensão de lista proposta por @ daniel-lew é mais pythônica.
Ioannis Filippidis

2
Sem discussão. Respondi à pergunta conforme perguntado, que geralmente é como um novato em python deseja pensar no problema, mas isso não significa que essa é a melhor maneira de responder.
David Berger

1
Python deve ser consistente com seu próprio modelo de dados e fazer a mesma coisa para todos os primitivos e agregados.
Terrence Brannon,

2
Eu acho que o comportamento padrão para listas python é totalmente errado. Eu esperaria isso str()em uma lista retornada str()para cada um dos elementos individuais dentro.
SuperGeo

21

Você pode usar uma compreensão de lista para gerar uma nova lista com cada item str () 'd automaticamente:

print([str(item) for item in mylist])

6
Ou apenas print(map(str, mylist))- é um pouco mais curto
anula de

4
Um problema com isso é se o item em minha lista também pode ser uma lista
Breandán Dalton

7

Duas coisas fáceis que você pode fazer, usar a mapfunção ou usar uma compreensão.

Mas isso dá a você uma lista de strings, não uma string. Portanto, você também precisa juntar as cordas.

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

ou

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

Em seguida, você pode imprimir este objeto de string composto.

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

4

Dependendo da finalidade para a qual você deseja usar essa saída, talvez __repr__seja mais apropriado:

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()

3

Eu concordo com a resposta anterior sobre o uso de compreensões de lista para fazer isso, mas você certamente poderia esconder isso atrás de uma função, se é isso que faz seu barco flutuar.

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]

Apenas por diversão, fiz list_str () recursivamente str () tudo contido na lista.


+1 Isso é útil ao implementar __str__e __repr__separadamente
vincent gravitas


0

Isso deve bastar.

Ao imprimir listas, bem como outras classes de contêineres, os elementos contidos serão impressos usando __repr__, porque __repr__deve ser usado para representação de objetos internos. Se ligarmos: help(object.__repr__)ele nos dirá:

Help on wrapper_descriptor:

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

E se chamarmos help(repr), a saída será:

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.

Se __str__for implementado para um objeto e __repr__não for repr(obj), produzirá a saída padrão, assim como print(obj)quando nenhum desses for implementado.

Portanto, a única maneira é implementar __repr__para sua classe. Uma maneira possível de fazer isso é:

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 

-3

A saída que você está obtendo é apenas o nome do módulo do objeto, o nome da classe e o endereço da memória em hexadecimal como o __repr__ função não é substituída.

__str__é usado para a representação de string de um objeto ao usar imprimir. Mas como você está imprimindo uma lista de objetos, e não iterando a lista para chamar o strmétodo para cada item, ele imprime a representação dos objetos.

Para ter a __str__função invocada, você precisa fazer algo assim:

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

Se você substituir a __repr__função, poderá usar o método de impressão como fazia 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

Então você obterá " my list is [1, 2, 3]" como sua saída.


Esta resposta parece responder a uma pergunta completamente não relacionada. Tem certeza de que o colocou no lugar certo?
Blckknght

Sim, Blckconhecia esta página que eu queria dar a minha resposta tinha um link para esta página de outro post. então me guiou aqui e eu respondo aqui supondo que o cara que fez a pergunta venha aqui novamente e veja minha resposta ... desculpe por o inconveniente !!!
panagiwtis koligas

Se a outra pergunta foi fechada como uma duplicata desta, é como se presumisse que as respostas existentes aqui já deveriam cuidar da outra pergunta. Se esse não for o caso, você deve sinalizar para reabrir essa pergunta, em vez de postar uma resposta incompreensível aqui, que quase certamente será excluída. Agora, é possível que você tenha algo a dizer que não seja abordado por nenhuma das 8 outras respostas aqui, mas você precisa fazer sua resposta fazer sentido no contexto desta página, uma vez que é a esta pergunta que você está respondendo. E não poste duas respostas idênticas!
Blckknght

1
Oh, embora agora que olhei para ele novamente, parece que @charliebeckwith editou sua postagem para ser completamente diferente, em vez de postar sua própria resposta, por algum motivo inexplicável. Normalmente não é assim que as edições funcionam ...
Blckknght

@blckknght Eu comecei a editá-lo antes de perceber como a resposta estava errada. Completamente inexplicável porque eu continuei.
charliebeckwith
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.