Python __str__ und Listen

107

Wenn ich in Java List.toString () aufrufe, wird automatisch die toString () -Methode für jedes Objekt in der Liste aufgerufen. Wenn meine Liste beispielsweise die Objekte o1, o2 und o3 enthält, sieht list.toString () ungefähr so ​​aus:

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

Gibt es eine Möglichkeit, ein ähnliches Verhalten in Python zu erzielen? Ich habe in meiner Klasse eine __str __ () -Methode implementiert, aber wenn ich eine Liste von Objekten drucke, verwende ich:

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

es sieht ungefähr so ​​aus:

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

Wie kann ich Python dazu bringen, mein __str__ automatisch für jedes Element in der Liste aufzurufen (oder diesbezüglich zu diktieren)?

benhsu
quelle
Nur als Referenz gibt es PEP 3140: "str (Container) sollte str (Element) aufrufen, nicht repr (Element)" , das abgelehnt wurde.
Alexey

Antworten:

133

Das Aufrufen eines Strings in einer Python-Liste ruft die __repr__Methode für jedes Element im Inneren auf. Für einige Artikel __str__und __repr__sind gleich. Wenn Sie dieses Verhalten wünschen, gehen Sie wie folgt vor:

def __str__(self):
    ...
def __repr__(self):
    return self.__str__()
David Berger
quelle
7
Die Identifikation __str__mit __repr__stimmt normalerweise nicht mit dem Python-Datenmodell überein , daher ist die von @ daniel-lew vorgeschlagene Lösung für das Listenverständnis pythonischer.
Ioannis Filippidis
2
Kein Argument. Ich habe die Frage wie gestellt beantwortet. So möchte ein Python-Neuling oft über das Problem nachdenken, aber das bedeutet nicht, dass dies der beste Weg ist, um zu antworten.
David Berger
1
Python sollte mit seinem eigenen Datenmodell konsistent sein und für alle Grundelemente und Aggregate dasselbe tun.
Terrence Brannon
2
Ich denke, das Standardverhalten für Python-Listen ist einfach falsch. Ich würde erwarten, dass str()auf einer Liste str()für jedes einzelne Element darin zurückgegeben.
SuperGeo
21

Sie können ein Listenverständnis verwenden , um mit jedem Element eine neue Liste zu erstellen. Str () würde automatisch:

print([str(item) for item in mylist])
Dan Lew
quelle
6
Oder einfach print(map(str, mylist))- es ist ein bisschen kürzer
Anula
4
Ein Problem dabei ist, wenn das Element in meiner Liste auch eine Liste sein könnte
Breandán Dalton
7

Zwei einfache Dinge, die Sie tun können, die mapFunktion verwenden oder ein Verständnis verwenden.

Damit erhalten Sie jedoch eine Liste von Zeichenfolgen, keine Zeichenfolge. Sie müssen also auch die Saiten zusammenfügen.

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

oder

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

Anschließend können Sie dieses zusammengesetzte Zeichenfolgenobjekt drucken.

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

Je nachdem, wofür Sie diese Ausgabe verwenden möchten, ist dies __repr__möglicherweise besser geeignet:

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
quelle
3

Ich stimme der vorherigen Antwort über die Verwendung von Listenverständnissen zu, aber Sie könnten dies sicherlich hinter einer Funktion verbergen, wenn dies das ist, was Ihr Boot schwimmt.

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]

Nur zum Spaß habe ich list_str () rekursiv str () alles gemacht, was in der Liste enthalten ist.

Jeremy Cantrell
quelle
+1 Dies ist nützlich bei der Implementierung __str__und __repr__separat
Vincent Gravitas
0

Etwas wie das?

a = [1, 2 ,3]
[str(x) for x in a]
# ['1', '2', '3']
Was macht er
quelle
0

Das sollte ausreichen.

Beim Drucken von Listen sowie anderen Containerklassen werden die enthaltenen Elemente mit gedruckt __repr__, da __repr__sie für die interne Objektdarstellung verwendet werden sollen. Wenn wir anrufen: help(object.__repr__)wird es uns sagen:

Help on wrapper_descriptor:

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

Und wenn wir es nennen help(repr), wird Folgendes ausgegeben:

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.

Wenn __str__für ein Objekt implementiert ist und __repr__nicht, repr(obj)wird die Standardausgabe ausgegeben, genau wieprint(obj) wenn keine von diesen implementiert sind.

Der einzige Weg ist also, __repr__für Ihre Klasse zu implementieren . Ein möglicher Weg, dies zu tun, ist folgender:

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
quelle
-3

Die Ausgabe, die Sie erhalten, ist nur der Modulname des Objekts, der Klassenname und dann die Speicheradresse in hexadezimaler Reihenfolge als die __repr__ Funktion nicht überschrieben wird.

__str__wird für die Zeichenfolgendarstellung eines Objekts bei Verwendung von print verwendet. Aber da Sie eine Liste von Objekten drucken und nicht über die Liste iterieren, um die aufzurufenstr Methode für jedes Element .

Um die __str__Funktion aufzurufen, müssen Sie Folgendes tun:

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

Wenn Sie die __repr__Funktion überschreiben, können Sie die Druckmethode wie zuvor verwenden:

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

Dann erhalten Sie " my list is [1, 2, 3]" als Ausgabe.

panagiwtis koligas
quelle
Diese Antwort scheint eine völlig unabhängige Frage zu beantworten. Sind Sie sicher, dass Sie es an der richtigen Stelle platzieren?
Blckknght
Ja, diese Seite, auf die ich meine Antwort geben wollte, hatte einen Link zu dieser Seite aus einem anderen Beitrag. Also hat sie mich hierher geführt und ich antworte hier, vorausgesetzt, der Typ, der die Frage gestellt hat, wird wieder hierher kommen und meine Antwort sehen die Unannehmlichkeiten !!!
Panagiwtis Koligas
Wenn die andere Frage als Duplikat dieser Frage geschlossen wurde, wird davon ausgegangen, dass sich die hier vorhandenen Antworten bereits um die andere Frage kümmern sollten. Wenn dies nicht der Fall ist, sollten Sie markieren, um diese Frage erneut zu öffnen, anstatt hier eine unverständliche Antwort zu veröffentlichen, die mit ziemlicher Sicherheit gelöscht wird. Nun ist es möglich, dass Sie etwas zu sagen haben, das nicht durch eine der 8 anderen Antworten hier abgedeckt ist, aber Sie müssen Ihre Antwort im Kontext dieser Seite sinnvoll gestalten, da es sich um diese Frage handelt, die Sie beantworten. Und poste keine zwei identischen Antworten!
Blckknght
1
Oh, obwohl ich es mir jetzt noch einmal anschaue, scheint es, dass @charliebeckwith Ihren Beitrag aus einem unerklärlichen Grund so bearbeitet hat, dass er völlig anders ist, als eine eigene Antwort zu veröffentlichen. So funktionieren Bearbeitungen normalerweise nicht ...
Blckknght
@blckknght Ich habe angefangen, es zu bearbeiten, bevor mir klar wurde, wie falsch die Antwort war. Völlig unerklärlich, warum ich weitermachte.
Charliebeck mit