Wie drucke ich Instanzen einer Klasse mit print ()?

538

Ich lerne die Seile in Python. Wenn ich versuche, ein Klassenobjekt Foobarmit der print()Funktion zu drucken , erhalte ich eine Ausgabe wie folgt:

<__main__.Foobar instance at 0x7ff2a18c>

Gibt es eine Möglichkeit, das Druckverhalten (oder die Zeichenfolgendarstellung ) einer Klasse und ihrer Objekte festzulegen ? Wenn ich beispielsweise print()ein Klassenobjekt aufrufe, möchte ich seine Datenelemente in einem bestimmten Format drucken. Wie erreicht man das in Python?

Wenn Sie mit C ++ - Klassen vertraut sind, können Sie dies für den Standard erreichen, ostreamindem Sie eine friend ostream& operator << (ostream&, const Foobar&)Methode für die Klasse hinzufügen .

Ashwin Nanjappa
quelle

Antworten:

628
>>> class Test:
...     def __repr__(self):
...         return "Test()"
...     def __str__(self):
...         return "member of Test"
... 
>>> t = Test()
>>> t
Test()
>>> print(t)
member of Test

Die __str__Methode passiert, wenn Sie sie drucken, und die __repr__Methode passiert, wenn Sie die repr()Funktion verwenden (oder wenn Sie sie mit der interaktiven Eingabeaufforderung betrachten). Wenn dies nicht die pythonischste Methode ist, entschuldige ich mich, weil ich auch noch lerne - aber es funktioniert.

Wenn keine __str__Methode angegeben ist, druckt Python __repr__stattdessen das Ergebnis von . Wenn Sie definieren, __str__aber nicht __repr__, verwendet Python das, was Sie oben als das sehen __repr__, aber weiterhin __str__zum Drucken.

Chris Lutz
quelle
11
Es gibt auch eine Unicode- Methode, die Sie anstelle von Str verwenden können . Beachten Sie, dass es ein Unicode-Objekt zurückgeben sollte, keine Zeichenfolge (aber wenn Sie eine Zeichenfolge zurückgeben, wird die Konvertierung in Unicode trotzdem durchgeführt ...)
Kender
@kender - Ich wusste nichts davon, aber im Nachhinein macht es angesichts der kaputten Unicode-Behandlung von Python 2.x durchaus Sinn.
Chris Lutz
11
Ich denke, diese Antwort kann nicht ohne einen Link zu dieser anderen vervollständigt werden !
tnotstar
Rettete mich! Nach der erneuten Implementierung der Methode __repr __ (self) führt print die Benutzer jedoch in die Irre. Kennen Sie Best Practices in diesem Bereich?
Viet
10
Für Java-Programmierer: __str __ (self) ist wie das toString () der Python-Welt
Janac Meena
134

Wie Chris Lutz erwähnte , wird dies durch die __repr__Methode in Ihrer Klasse definiert.

Aus der Dokumentation von repr():

Bei vielen Typen versucht diese Funktion, eine Zeichenfolge zurückzugeben, die bei Übergabe ein Objekt mit demselben Wert ergibt eval(). Andernfalls ist die Darstellung eine Zeichenfolge in spitzen Klammern, die den Namen des Objekttyps zusammen mit zusätzlichen Informationen enthält oft einschließlich des Namens und der Adresse des Objekts. Eine Klasse kann steuern, was diese Funktion für ihre Instanzen zurückgibt, indem sie eine __repr__()Methode definiert.

Bei folgendem Klassentest:

class Test:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __repr__(self):
        return "<Test a:%s b:%s>" % (self.a, self.b)

    def __str__(self):
        return "From str method of Test: a is %s, b is %s" % (self.a, self.b)

..es wird sich in der Python-Shell folgendermaßen verhalten:

>>> t = Test(123, 456)
>>> t
<Test a:123 b:456>
>>> print repr(t)
<Test a:123 b:456>
>>> print(t)
From str method of Test: a is 123, b is 456
>>> print(str(t))
From str method of Test: a is 123, b is 456

Wenn keine __str__Methode definiert ist, verwendet print(t)(oder print(str(t))) __repr__stattdessen das Ergebnis von

Wenn keine __repr__Methode definiert ist, wird der Standardwert verwendet, der ziemlich genau dem entspricht.

def __repr__(self):
    return "<%s instance at %s>" % (self.__class__.__name__, id(self))
dbr
quelle
+1, aber Ihr Klassencode __str__unterscheidet sich von den Ergebnissen der interaktiven Shell, die Sie angeben. : P
Chris Lutz
1
Err, oops .. das manuelle Ändern der REPL-Ausgabe endet nie gut. Ich sollte wahrscheinlich meine Beiträge bearbeiten: P
dbr
1
Die %String - Formatierung wird nicht mehr unterstützt, von docs.python.org/whatsnew/2.6.html „der Operator% wird ergänzt durch eine leistungsfähigere String Formatierung Methode, Format ()“
dbr
4
Dbr: Das stimmt. Beachten Sie, dass im Dokument "Was ist neu in Python 3.0?" Auch "format () -Methode [...]" angegeben ist. Es ist geplant, dies schließlich zur einzigen API für die Formatierung von Zeichenfolgen zu machen und den% -Operator in Python 3.1 zu verwerfen.
Ashwin Nanjappa
1
Schade, %war sehr praktisch.
Janusz Lenar
52

Eine generische Methode, die ohne spezifische Formatierung auf jede Klasse angewendet werden kann, kann wie folgt erfolgen:

class Element:
    def __init__(self, name, symbol, number):
        self.name = name
        self.symbol = symbol
        self.number = number

    def __str__(self):
        return str(self.__class__) + ": " + str(self.__dict__)

Und dann,

elem = Element('my_name', 'some_symbol', 3)
print(elem)

produziert

__main__.Element: {'symbol': 'some_symbol', 'name': 'my_name', 'number': 3}
user394430
quelle
23

Wenn Sie sich in einer Situation wie @Keith befinden, können Sie Folgendes versuchen:

print a.__dict__

Es widerspricht dem, was ich für guten Stil halte, aber wenn Sie nur versuchen zu debuggen, sollte es tun, was Sie wollen.

John
quelle
Möchten Sie wissen, ob der Diktatschlüssel Objekte in seinen Werten enthält?
Pranaygoyal02
1
@HadoopEvangelist Fragen Sie sich, wie Sie diese Objekte auch rekursiv drucken oder nur feststellen können, ob es Objekte gibt?
John
13

Um meine zwei Cent zu @ dbrs Antwort hinzuzufügen, folgt ein Beispiel für die Implementierung dieses Satzes aus der offiziellen Dokumentation, die er zitiert hat:

"[...] um einen String zurückzugeben, der ein Objekt mit demselben Wert ergibt, wenn er an eval () übergeben wird, [...]"

Angesichts dieser Klassendefinition:

class Test(object):
    def __init__(self, a, b):
        self._a = a
        self._b = b

    def __str__(self):
        return "An instance of class Test with state: a=%s b=%s" % (self._a, self._b)

    def __repr__(self):
        return 'Test("%s","%s")' % (self._a, self._b)

Jetzt ist es einfach, Instanz der TestKlasse zu serialisieren :

x = Test('hello', 'world')
print 'Human readable: ', str(x)
print 'Object representation: ', repr(x)
print

y = eval(repr(x))
print 'Human readable: ', str(y)
print 'Object representation: ', repr(y)
print

Wenn wir also den letzten Code ausführen, erhalten wir:

Human readable:  An instance of class Test with state: a=hello b=world
Object representation:  Test("hello","world")

Human readable:  An instance of class Test with state: a=hello b=world
Object representation:  Test("hello","world")

Aber wie gesagt in meinem letzten Kommentar: Mehr Infos gibt es einfach hier !

tnotstar
quelle
12

Sie müssen verwenden __repr__. Dies ist eine Standardfunktion wie __init__. Zum Beispiel:

class Foobar():
    """This will create Foobar type object."""

    def __init__(self):
        print "Foobar object is created."

    def __repr__(self):
        return "Type what do you want to see here."

a = Foobar()

print a
flow_chart
quelle
2
repr und str haben unterschiedliche Semantiken: repr sollte eine Python-Quelle sein, die dasselbe Objekt (neu) erstellen würde - dies ist seine repr esentation in Code; str sollte eine hübsche Userland-Stringifizierung des Objekts sein.
Eric Towers
12

Eine schönere Version der Antwort von @ user394430

class Element:
    def __init__(self, name, symbol, number):
        self.name = name
        self.symbol = symbol
        self.number = number

    def __str__(self):
        return  str(self.__class__) + '\n'+ '\n'.join(('{} = {}'.format(item, self.__dict__[item]) for item in self.__dict__))

elem = Element('my_name', 'some_symbol', 3)
print(elem)

Erzeugt eine visuell schöne Liste der Namen und Werte.

<class '__main__.Element'>
name = my_name
symbol = some_symbol
number = 3

Eine noch schickere Version (danke Ruud) sortiert die Artikel:

def __str__(self):
    return  str(self.__class__) + '\n' + '\n'.join((str(item) + ' = ' + str(self.__dict__[item]) for item in sorted(self.__dict__)))
MikeyB
quelle
8

Für Python 3:

Wenn das spezifische Format nicht wichtig ist (z. B. zum Debuggen), erben Sie einfach von der unten stehenden Printable-Klasse. Sie müssen nicht für jedes Objekt Code schreiben.

Inspiriert von dieser Antwort

class Printable:
    def __repr__(self):
        from pprint import pformat
        return "<" + type(self).__name__ + "> " + pformat(vars(self), indent=4, width=1)

# Example Usage
class MyClass(Printable):
    pass

my_obj = MyClass()
my_obj.msg = "Hello"
my_obj.number = "46"
print(my_obj)
PeterM
quelle
1

Es gibt bereits viele Antworten in diesem Thread, aber keine davon hat mir besonders geholfen. Ich musste es selbst herausfinden, also hoffe ich, dass diese etwas informativer ist.

Sie müssen nur sicherstellen, dass Sie am Ende Ihrer Klasse Klammern haben, z.

print(class())

Hier ist ein Beispiel für Code aus einem Projekt, an dem ich gearbeitet habe:

class Element:
    def __init__(self, name, symbol, number):
        self.name = name
        self.symbol = symbol
        self.number = number
    def __str__(self):
        return "{}: {}\nAtomic Number: {}\n".format(self.name, self.symbol, self.number

class Hydrogen(Element):
    def __init__(self):
        super().__init__(name = "Hydrogen", symbol = "H", number = "1")

Um meine Wasserstoffklasse zu drucken, habe ich Folgendes verwendet:

print(Hydrogen())

Bitte beachten Sie, dass dies ohne die Klammern am Ende von Wasserstoff nicht funktioniert. Sie sind notwendig.

Hoffe das hilft, lass es mich wissen, wenn du noch Fragen hast.

Stumpy
quelle