Python __str__ e liste


107

In Java, se chiamo List.toString (), chiamerà automaticamente il metodo toString () su ogni oggetto all'interno di List. Ad esempio, se il mio elenco contiene oggetti o1, o2 e o3, list.toString () sarebbe simile a questo:

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

C'è un modo per ottenere un comportamento simile in Python? Ho implementato un metodo __str __ () nella mia classe, ma quando stampo un elenco di oggetti, usando:

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

assomiglia a questo:

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

come posso fare in modo che python chiami automaticamente il mio __str__ per ogni elemento all'interno della lista (o dict per quella materia)?


Risposte:


133

La chiamata di stringa su un elenco Python chiama il __repr__metodo su ogni elemento all'interno. Per alcuni articoli __str__e __repr__sono gli stessi. Se vuoi quel comportamento, fai:

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

7
L'identificazione __str__con di __repr__solito non è d'accordo con il modello di dati Python , quindi la soluzione di comprensione dell'elenco proposta da @ daniel-lew è più pitonica.
Ioannis Filippidis

2
Nessun argomento. Ho risposto alla domanda come chiesto, che spesso è il modo in cui un nuovo arrivato in Python vuole pensare al problema, ma questo non significa che sia il modo migliore per rispondere.
David Berger

1
Python dovrebbe essere coerente con il proprio modello di dati e fare la stessa cosa per tutte le primitive e gli aggregati.
Terrence Brannon

2
Penso che il comportamento predefinito per gli elenchi di Python sia chiaramente sbagliato. Mi aspetto che str()su un elenco restituito str()per ciascuno dei singoli elementi all'interno.
SuperGeo

21

È possibile utilizzare una comprensione della lista per generare automaticamente una nuova lista con ogni elemento str () 'd:

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

6
O semplicemente print(map(str, mylist))- è un po 'più breve
anula

4
Un problema con questo è se l'elemento nella mia lista potrebbe anche essere un elenco
Breandán Dalton

7

Due semplici cose che puoi fare, usa la mapfunzione o usa una comprensione.

Ma questo ti dà un elenco di stringhe, non una stringa. Quindi devi anche unire le corde insieme.

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

o

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

Quindi puoi stampare questo oggetto stringa composta.

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

4

A seconda di ciò per cui desideri utilizzare quell'output, forse __repr__potrebbe essere più appropriato:

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

Sono d'accordo con la risposta precedente sull'uso delle comprensioni delle liste per fare ciò, ma potresti certamente nasconderlo dietro una funzione, se è questo che fa galleggiare la tua barca.

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 per divertimento, ho creato list_str () ricorsivamente str () tutto ciò che è contenuto nell'elenco.


+1 Questo è utile durante l'implementazione __str__e __repr__separatamente
vincent gravitas


0

Questo dovrebbe essere sufficiente.

Quando si stampano elenchi e altre classi contenitore, gli elementi contenuti verranno stampati utilizzando __repr__, perché __repr__è pensato per essere utilizzato per la rappresentazione di oggetti interni. Se chiamiamo: help(object.__repr__)ci dirà:

Help on wrapper_descriptor:

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

E se lo chiamiamo help(repr)produrrà:

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.

If __str__è implementato per un oggetto e __repr__non è repr(obj)restituito l'output predefinito, proprio come print(obj)quando non sono implementati.

Quindi l'unico modo è implementare __repr__per la tua classe. Un modo possibile per farlo è questo:

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

L'output che stai ottenendo è solo il nome del modulo dell'oggetto, il nome della classe e quindi l'indirizzo di memoria in esadecimale poiché la __repr__funzione non viene sovrascritta.

__str__viene utilizzato per la rappresentazione di stringa di un oggetto quando si utilizza print. Ma poiché stai stampando un elenco di oggetti e non iterando sulla lista per chiamare il strmetodo per ogni elemento, stampa la rappresentazione degli oggetti.

Per avere la __str__funzione invocata dovresti fare qualcosa del genere:

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

Se sovrascrivi la __repr__funzione puoi usare il metodo di stampa come facevi prima:

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

Quindi otterrai " my list is [1, 2, 3]" come output.


Questa risposta sembra rispondere a una domanda completamente non correlata. Sei sicuro di averlo messo nel posto giusto?
Blckknght

sì Blckknght questa pagina che volevo dare la mia risposta aveva un link a questa pagina da un altro post. quindi mi ha guidato qui e rispondo qui supponendo che il ragazzo che ha fatto la domanda verrà di nuovo qui e vedrà la mia risposta .. scusate per l'inconveniente !!!
panagiwtis koligas

Se l'altra domanda è stata chiusa come un duplicato di questa, si presume che le risposte esistenti qui dovrebbero già occuparsi dell'altra domanda. Se non è così, dovresti contrassegnare per riaprire la domanda, invece di pubblicare una risposta incomprensibile qui, che quasi sicuramente verrà eliminata. Ora, è possibile che tu abbia qualcosa da dire che non è coperto da una delle altre 8 risposte qui, ma dovresti fare in modo che la tua risposta abbia un senso nel contesto di questa pagina, poiché è questa domanda a cui stai rispondendo. E non pubblicare due risposte identiche!
Blckknght

1
Oh, anche se ora che lo guardo di nuovo, sembra che @charliebeckwith abbia modificato il tuo post in modo che sia completamente diverso, piuttosto che pubblicare la propria risposta, per qualche motivo inspiegabile. Normalmente non è così che funzionano le modifiche ...
Blckknght

@blckknght Ho iniziato a modificarlo prima di rendermi conto di quanto fosse sbagliata la risposta. Completamente inspiegabile il motivo per cui ho continuato.
charliebeck con il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.