Python: Was ist der Unterschied zwischen __str__ und __repr__?

Beide machen aus einem Objekt einen String. __str__ ist für Menschen, __repr__ ist für dich, wenn etwas schiefgegangen ist — und wenn du nur eine von beiden definierst, dann __repr__.

Der Unterschied bei eingebauten Typen

str : a string                     repr : 'a string'
str : 3.0                          repr : 3.0
str : 2026-08-29                   repr : datetime.date(2026, 8, 29)
str : 0.1                          repr : Decimal('0.1')
str : None                         repr : None

Die Zeile mit dem Datum zeigt die Absicht. str liefert dir etwas für eine Seite, repr liefert dir etwas, das genau sagt was das Objekt ist — samt Typ.

Die Zeile mit dem String ist die, der man täglich begegnet: repr behält die Anführungszeichen, du kannst also 1 von "1" unterscheiden.

Wo du welche bekommst

print(s)   : line
break
print([s]) : ['line\nbreak']

print() verwendet str. Ein Container verwendet repr für seine Elemente — immer, auch wenn du den Container ausgibst. Deshalb sieht eine Liste deiner Objekte anders aus, als eines davon auszugeben.

Der interaktive Interpreter gibt repr aus. Deshalb zeigt ein Wert an der Eingabeaufforderung Anführungszeichen und print() nicht.

In einem f-String wählst du selbst: !s für str, !r für repr.

Definiere zuerst repr

Das ist die praktische Regel, und sie folgt aus einem Rückfallweg:

class NurRepr:
    def __repr__(self): return "NurRepr(x=1)"
str(o)  : OnlyRepr(x=1)
repr(o) : OnlyRepr(x=1)

str() fällt auf __repr__ zurück, wenn es kein __str__ gibt. Nur __repr__ zu definieren liefert dir also überall eine brauchbare Ausgabe.

Umgekehrt gilt das nicht:

with only __str__, repr(p) : <__main__.OnlyStr object at 0x...
[p] in a list : [<__main__.OnlyStr object at 0x7ede07e3738...

Definierst du nur __str__, sind deine Objekte in einer Liste, einem Dictionary, einem Debugger oder einer protokollierten Datenstruktur unlesbar — also genau dann, wenn du sie lesen musst.

Beide, wenn sie sich unterscheiden

class Geldbetrag:
    def __init__(self, c): self.cent = c
    def __repr__(self): return f"Geldbetrag(cent={self.cent})"
    def __str__(self): return f"{self.cent / 100:.2f} EUR"
print(m) : 4.99 EUR
repr(m)  : Money(cents=499)
[m]      : [Money(cents=499)]

Der Benutzer sieht 4.99 EUR. Du siehst Money(cents=499), und das sagt dir, dass es Cent sind und keine Euro — genau die Unterscheidung, die man um drei Uhr morgens gerne hätte.

Die Regel für repr

Die Dokumentation verlangt etwas Eindeutiges, und idealerweise etwas, das man wieder einfügen könnte:

repr(a date) : datetime.date(2026, 8, 29)
eval works?  : True
str(a date)  : 2026-08-29   <- not valid Python

eval(repr(x)) == x ist ein Ziel und keine Pflicht — viele Objekte schaffen das nicht. Wenn es nicht geht, sind spitze Klammern die Konvention, um “das ist eine Beschreibung und kein Ausdruck” zu signalisieren:

def __repr__(self):
    return f"<Verbindung zu {self.host}, {'offen' if self.offen else 'geschlossen'}>"

Der Fall mit den Fließkommazahlen

str  : 0.30000000000000004
repr : 0.30000000000000004
float(repr(f)) == f : True

Seit Python 3.1 stimmen die beiden bei Fließkommazahlen überein, und beide liefern den kürzesten String, der exakt zurückkonvertiert. Davor rundete str() auf 12 signifikante Stellen und repr() gab 17 aus — daher stammt der alte Rat, die beiden würden sich unterscheiden. Er ist überholt.

Protokolliere repr, nicht str

str(exc)  : division by zero
repr(exc) : ZeroDivisionError('division by zero')

str() einer Exception liefert die Nachricht und sonst nichts. repr() liefert die Nachricht und den Typ. In einer Logdatei ist “division by zero” ohne den Klassennamen deutlich weniger wert, und der Unterschied kostet nichts.

Dieselbe Überlegung gilt für logging: %r statt %s für alles, was du später einmal identifizieren musst.

Ein Hinweis zu dataclasses

@dataclass erzeugt dir ein __repr__, und zwar genau in der oben beschriebenen Form. Für einen einfachen Datencontainer bekommst du das also geschenkt und solltest keines von Hand schreiben. Ein __str__ wird nicht erzeugt, und das ist die richtige Voreinstellung — die meisten Objekte brauchen keines.

Hinweis zu Netcup (Werbung)

Der deutsche Hoster Netcup bietet unter anderem günstige und zugleich leistungsstarke Webhosting Pakete, KVM-basierte Root Server und dezidierte Server an. Mit unseren Gutscheincodes kannst du noch mehr Geld sparen (6€ bei deiner ersten Bestellung, 30% Rabatt auf alle KVM-basierten Root Server, ...).