PEP 223 – Bedeutung von \x-Escapes ändern
- Autor:
- Tim Peters <tim.peters at gmail.com>
- Status:
- Final
- Typ:
- Standards Track
- Erstellt:
- 20. Aug. 2000
- Python-Version:
- 2.0
- Post-History:
- 23. Aug. 2000
Zusammenfassung
Ändern Sie \x-Escapes, sowohl in 8-Bit- als auch in Unicode-Strings, so, dass sie genau die beiden folgenden Hexadezimalziffern verbrauchen. Der Vorschlag betrachtet dies als Korrektur eines ursprünglichen Designfehlers, was zu einer klareren Ausdrucksweise in allen String-Arten, einer saubereren Unicode-Handhabung, besserer Kompatibilität mit Perl-Regulären Ausdrücken und einem minimalen Risiko für bestehenden Code führt.
Syntax
Die Syntax von \x-Escapes in allen nicht-rohen String-Arten wird wie folgt:
\xhh
wobei h eine Hexadezimalziffer ist (0-9, a-f, A-F). Die genaue Syntax in 1.5.2 ist im Referenzhandbuch nicht klar spezifiziert; es besagt
\xhh...
was "zwei oder mehr" Hexadezimalziffern impliziert, aber auch Ein-Ziffer-Formen werden vom 1.5.2-Compiler akzeptiert, und ein einfaches \x wird zu sich selbst "expandiert" (d. h. ein Backslash gefolgt vom Buchstaben x). Es ist unklar, ob das Referenzhandbuch eines der Ein-Ziffer- oder Null-Ziffer-Verhaltensweisen beabsichtigte.
Semantik
In einem 8-Bit-Nicht-Rohen-String
\xij
wird zu dem Zeichen
chr(int(ij, 16))
beexpandiert. Beachten Sie, dass dies dasselbe ist wie in 1.6 und früher.
In einem Unicode-String
\xij
verhält sich gleich wie
\u00ij
d. h. es wird zum offensichtlichen Latin-1-Zeichen aus dem Anfangsbereich des Unicode-Raums expandiert.
Ein \x, dem mindestens zwei Hexadezimalziffern folgen, ist ein Kompilierungsfehler, speziell ValueError in 8-Bit-Strings und UnicodeError (eine Unterklasse von ValueError) in Unicode-Strings. Beachten Sie, dass, wenn einem \x mehr als zwei Hexadezimalziffern folgen, nur die ersten beiden "verbraucht" werden. In 1.6 und früher wurden alle außer den *letzten* beiden stillschweigend ignoriert.
Beispiel
In 1.5.2
>>> "\x123465" # same as "\x65"
'e'
>>> "\x65"
'e'
>>> "\x1"
'\001'
>>> "\x\x"
'\\x\\x'
>>>
In 2.0
>>> "\x123465" # \x12 -> \022, "3456" left alone
'\0223456'
>>> "\x65"
'e'
>>> "\x1"
[ValueError is raised]
>>> "\x\x"
[ValueError is raised]
>>>
Geschichte und Begründung
\x-Escapes wurden in C eingeführt, um variable Zeichenkodierungen zu spezifizieren. Genau welche Kodierungen das waren und wie viele Hexadezimalziffern sie benötigten, wurde jeder Implementierung überlassen. Die Sprache besagte einfach, dass \x *alle* folgenden Hexadezimalziffern "verbrauchte" und die Bedeutung der jeweiligen Implementierung überließ. So war im Grunde \x in C ein Standard-Hook zur Bereitstellung plattformdefinierter Verhaltensweisen.
Da Python explizit auf Plattformunabhängigkeit abzielt, wurde der \x-Escape in Python (bis einschließlich 1.6) auf allen Plattformen gleich behandelt: alle *außer* den letzten beiden Hexadezimalziffern wurden stillschweigend ignoriert. Der einzige tatsächliche Nutzen für \x-Escapes in Python bestand darin, ein einzelnes Byte mit Hexadezimalnotation zu spezifizieren.
Larry Wall scheint erkannt zu haben, dass dies der einzige wirkliche Nutzen für \x-Escapes in einer plattformunabhängigen Sprache war, da die vorgeschlagene Regel für Python 2.0 tatsächlich das ist, was Perl von Anfang an getan hat (obwohl man im Perl -w-Modus laufen muss, um bei \x-Escapes mit weniger als 2 folgenden Hexadezimalziffern gewarnt zu werden – es ist eindeutig Python-konformer, immer 2 zu verlangen).
Als Unicode-Strings in Python eingeführt wurden, wurde \x verallgemeinert, so dass in Unicode-Strings alle außer den letzten *vier* Hexadezimalziffern ignoriert wurden. Dies verursachte eine technische Schwierigkeit für die neue reguläre Ausdrucks-Engine: SRE versucht sehr stark, das Mischen von 8-Bit- und Unicode-Mustern und -Strings auf intuitive Weise zu ermöglichen, und es gab keine Möglichkeit mehr zu erraten, was zum Beispiel r"\x123456" als Muster bedeuten sollte: Soll es dem 8-Bit-Zeichen \x56 entsprechen oder dem Unicode-Zeichen \u3456?
Es gibt umständliche Wege zu raten, aber das ist noch nicht alles. Der ISO C99-Standard führt auch 8-stellige \U12345678-Escapes ein, um den gesamten ISO 10646-Zeichenraum abzudecken, und es ist auch gewünscht, dass Python 2 dies von Anfang an unterstützt. Aber was sollen dann \x-Escapes bedeuten? Ignorieren sie dann alle außer den letzten *acht* Hexadezimalziffern? Und wenn weniger als 8 folgen in einem Unicode-String, alle außer den letzten 4? Und wenn weniger als 4, alle außer den letzten 2?
Das wurde von Minute zu Minute unübersichtlicher, und der Vorschlag durchschlägt den Gordischen Knoten, indem er \x einfacher statt komplizierter macht. Beachten Sie, dass die 4-stellige Verallgemeinerung auf \xijkl in Unicode-Strings ebenfalls redundant war, da sie genau dasselbe bedeutete wie \uijkl in Unicode-Strings. Es ist Python-konformer, nur eine offensichtliche Möglichkeit zu haben, ein Unicode-Zeichen über Hexadezimalnotation zu spezifizieren.
Entwicklung und Diskussion
Der Vorschlag wurde zwischen Guido van Rossum, Fredrik Lundh und Tim Peters per E-Mail ausgearbeitet. Er wurde anschließend auf Python-Dev unter dem Betreff „Go x yourself“ [1] ab dem 20.08.2000 erklärt und diskutiert. Die Resonanz war überwältigend positiv; es wurden keine Einwände erhoben.
Abwärtskompatibilität
Die Änderung der Bedeutung von \x-Escapes birgt zwar das Risiko, bestehenden Code zu brechen, obwohl bisher keine Inkompatibilitäten entdeckt wurden. Das Risiko wird als minimal eingeschätzt.
Tim Peters hat bestätigt, dass es, abgesehen von Teilen der Standardtestsuite, die absichtlich Grenzfälle provozieren, keine Instanzen von \xabcdef... mit weniger oder mehr als 2 folgenden Hexadezimalziffern gibt, weder im Python CVS-Entwicklungsbaum noch in verschiedenen Python-Paketen, die auf seinem Rechner liegen.
Es ist unwahrscheinlich, dass es welche mit weniger als 2 gibt, da das Referenzhandbuch implizierte, dass sie nicht legal seien (obwohl dies diskutabel ist!). Wenn es welche mit mehr als 2 gibt, ist Guido bereit zu argumentieren, dass sie sowieso fehlerhaft waren <0.9 zwinker>.
Guido berichtete, dass die O’Reilly Python-Bücher *bereits* dokumentieren, dass Python auf die vorgeschlagene Weise funktioniert, wahrscheinlich aufgrund ihres Perl-Editing-Erbes (wie oben erwähnt, funktionierte Perl von Anfang an (sehr nahe an) der vorgeschlagenen Weise).
Finn Bock berichtete, dass das, was JPython mit \x-Escapes macht, heute unvorhersehbar ist. Dieser Vorschlag gibt eine klare Bedeutung, die konsistent und einfach über alle Python-Implementierungen hinweg implementiert werden kann.
Auswirkungen auf andere Werkzeuge
Es wird angenommen, dass es keine gibt. Die Kandidaten für Bruch wären hauptsächlich Parsing-Werkzeuge, aber der Autor kennt keine, die sich über die interne Struktur von Python-Strings Gedanken machen, über die Annäherung „wenn ein Backslash da ist, schluck den nächsten Charakter“. Tim Peters überprüfte python-mode.el, das std tokenize.py und pyclbr.py sowie das IDLE-Syntax-Highlighting-Subsystem und glaubt nicht, dass eine Änderung erforderlich ist. Werkzeuge wie tabnanny.py und checkappend.py erben ihre Immunität von tokenize.py.
Referenzimplementierung
Die Codeänderungen sind so einfach, dass kein separater Patch erstellt wird. Fredrik Lundh schreibt den Code, ist Experte auf diesem Gebiet und wird die Änderungen einfach vor der Veröffentlichung von 2.0b1 einchecken.
BDFL-Bekanntmachungen
Ja, ValueError, nicht SyntaxError. „Probleme mit literalen Interpretationen lösen traditionell 'Laufzeit'-Ausnahmen aus und keine Syntaxfehler.“
Referenzen
Urheberrecht
Dieses Dokument wurde gemeinfrei erklärt.
Quelle: https://github.com/python/peps/blob/main/peps/pep-0223.rst
Zuletzt geändert: 2025-02-01 08:55:40 GMT