Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python Enhancement Proposals

PEP 3140 – str(container) sollte str(item) aufrufen, nicht repr(item)

Autor:
Oleg Broytman <phd at phdru.name>, Jim J. Jewett <jimjjewett at gmail.com>
Discussions-To:
Python-3000 Liste
Status:
Abgelehnt
Typ:
Standards Track
Erstellt:
27. Mai 2008
Post-History:
28. Mai 2008

Inhaltsverzeichnis

Ablehnung

Guido sagte, dies würde zu viel Störung zu kurz vor Beta verursachen. Siehe [1].

Zusammenfassung

Dieses Dokument erörtert die Vor- und Nachteile der aktuellen Implementierung von str(container). Es erörtert auch die Vor- und Nachteile eines anderen Ansatzes – str(item) statt repr(item) aufzurufen.

Motivation

Aktuell ruft str(container) repr für Elemente auf. Argumente dafür

  • Container weigern sich zu erraten, was der Benutzer in str(container) sehen möchte – Umgebung, Trennzeichen usw.;
  • repr(item) zeigt normalerweise Typinformationen an – Anführungszeichen um Zeichenketten, Klassennamen usw.

Gegenargumente

  • Es ist unlogisch; str() soll __str__ aufrufen, falls vorhanden, nicht __repr__;
  • Es gibt keine Standardmethode, den Inhalt eines Containers auszugeben, indem die __str__ der Elemente aufgerufen werden, was in Fällen, in denen __str__ und __repr__ unterschiedliche Ergebnisse liefern, unpraktisch ist;
  • repr(item) macht manchmal falsche Dinge (z. B. hexadezimale Escape-Sequenzen für Nicht-ASCII-Zeichenketten)

Diese PEP schlägt vor, die Funktionsweise von str(container) zu ändern. Es wird vorgeschlagen, die Funktionsweise von repr(container) nachzuahmen, mit einer Ausnahme – str anstelle von repr für Elemente aufrufen. Dies ermöglicht es einem Benutzer, zu wählen, welche Ergebnisse er erhalten möchte – von item.__repr__ oder item.__str__.

Aktuelle Situation

Die meisten Containertypen (Tupel, Listen, Dictionaries, Mengen usw.) implementieren keine __str__-Methode, daher ruft str(container) container.__repr__ auf, und container.__repr__ vergisst, sobald es aufgerufen wird, dass es von str aufgerufen wurde, und ruft immer repr für die Elemente des Containers auf.

Dieses Verhalten hat Vor- und Nachteile. Ein Vorteil ist, dass die meisten Elemente mit Typinformationen dargestellt werden – Zeichenketten sind von Anführungszeichen umschlossen, Instanzen können sowohl den Klassennamen als auch die Instanzdaten enthalten

>>> print([42, '42'])
[42, '42']
>>> print([Decimal('42'), datetime.now()])
[Decimal("42"), datetime.datetime(2008, 5, 27, 19, 57, 43, 485028)]

Der Nachteil ist, dass __repr__ oft technische Daten (wie '<object at address>') oder unleserliche Zeichenketten (hexadezimal kodierte Zeichenketten, wenn die Eingabe eine Nicht-ASCII-Zeichenkette ist) zurückgibt.

>>> print(['тест'])
['\xd4\xc5\xd3\xd4']

Eine der Motivationen für PEP 3138 ist, dass weder repr noch str das sinnvolle Ausgeben von Dictionaries ermöglichen, deren Schlüssel Nicht-ASCII-Textzeichen sind. Da jetzt Unicode-Bezeichner erlaubt sind, gehören dazu auch die eigenen Attribut-Dictionaries von Python. Dies schließt auch die JSON-Serialisierung ein (und verursachte einige Schwierigkeiten für die json-Bibliothek).

PEP 3138 schlägt vor, dies zu beheben, indem die Invariante "repr ist sicheres ASCII" gebrochen wird und die Art und Weise geändert wird, wie repr (das für die Persistenz verwendet wird) einige Objekte ausgibt, mit systemabhängigen Fehlern.

Die Änderung der Funktionsweise von str(container) würde im Normalfall eine einfache Fehlersuche ermöglichen und die Sicherheit von Nur-ASCII für den maschinenlesbaren Fall beibehalten. Der einzige Nachteil ist, dass str(x) und repr(x) öfter unterschiedlich wären – aber nur in den Fällen, in denen die aktuelle fast gleiche Version unzureichend ist.

Es erscheint auch unlogisch, dass str(container) repr für Elemente aufruft und nicht str. Es ist nur logisch, den folgenden Code zu erwarten

class Test:
    def __str__(self):
        return "STR"

    def __repr__(self):
        return "REPR"


test = Test()
print(test)
print(repr(test))
print([test])
print(str([test]))

auszugeben

STR
REPR
[STR]
[STR]

wo er tatsächlich ausgibt

STR
REPR
[REPR]
[REPR]

Besonders unlogisch ist es, zu sehen, dass print in Python 2 str verwendet, wenn es auf etwas aufgerufen wird, das wie ein Tupel aussieht

>>> print Decimal('42'), datetime.now()
42 2008-05-27 20:16:22.534285

wo auf einem tatsächlichen Tupel es ausgibt

>>> print((Decimal('42'), datetime.now()))
(Decimal("42"), datetime.datetime(2008, 5, 27, 20, 16, 27, 937911))

Ein anderer Ansatz – str(item) aufrufen

Zum Beispiel sind bei Zahlen oft nur der Wert, der Menschen interessiert.

>>> print Decimal('3')
3

Aber das Einfügen des Wertes in eine Liste zwingt die Benutzer, die Typinformationen zu lesen, genau so, als ob repr zum Nutzen einer Maschine aufgerufen worden wäre.

>>> print [Decimal('3')]
[Decimal("3")]

Nach dieser Änderung würden die Typinformationen die str-Ausgabe nicht überladen.

>>> print "%s".format([Decimal('3')])
[3]
>>> str([Decimal('3')])  # ==
[3]

Aber sie wären immer noch verfügbar, wenn gewünscht.

>>> print "%r".format([Decimal('3')])
[Decimal('3')]
>>> repr([Decimal('3')])  # ==
[Decimal('3')]

Es gibt eine Reihe von Strategien, um das Problem zu lösen. Die radikalste ist, __repr__ so zu ändern, dass es einen neuen Parameter (Flag) akzeptiert: "von str aufgerufen, also rufe str für Elemente auf, nicht repr". Der Nachteil des Vorschlags ist, dass jede __repr__-Implementierung geändert werden muss. Introspektion könnte ein wenig helfen (prüfe __repr__ vor dem Aufruf, ob es 2 oder 3 Parameter akzeptiert), aber Introspektion funktioniert nicht bei in C geschriebenen Klassen, wie allen eingebauten Containern.

Ein weniger radikaler Vorschlag ist die Implementierung von __str__-Methoden für eingebaute Containertypen. Der offensichtliche Nachteil ist eine Verdoppelung des Aufwands – all diese __str__- und __repr__-Implementierungen unterscheiden sich nur in einem kleinen Detail – ob sie str oder repr für Elemente aufrufen.

Der konservativste Vorschlag ist, str nicht zu ändern, sondern Entwicklern zu ermöglichen, ihre eigenen anwendungs- oder bibliotheksspezifischen Pretty-Printer zu implementieren. Der Nachteil ist wiederum eine Multiplikation des Aufwands und die Verbreitung vieler kleiner spezifischer Container-Traversierungsalgorithmen.

Abwärtskompatibilität

In Fällen, in denen Typinformationen wichtiger sind als üblich, wird es immer noch möglich sein, die aktuellen Ergebnisse durch explizites Aufrufen von repr zu erhalten.

Referenzen


Quelle: https://github.com/python/peps/blob/main/peps/pep-3140.rst

Zuletzt geändert: 2025-02-01 08:59:27 GMT