PEP 331 – Locale-Unabhängige Float-/String-Konvertierungen
- Autor:
- Christian R. Reis <kiko at async.com.br>
- Status:
- Final
- Typ:
- Standards Track
- Erstellt:
- 19-Jul-2003
- Python-Version:
- 2.4
- Post-History:
- 21-Jul-2003, 13-Aug-2003, 18-Jun-2004
Zusammenfassung
Die Unterstützung für die LC_NUMERIC-Locale-Kategorie in Python 2.3 ist nur im Python-Bereich implementiert. Dies führt zu inkonsistentem Verhalten und Thread-Sicherheitsproblemen für Anwendungen, die Erweiterungsmodule und in C implementierte Bibliotheken verwenden, die Gleitkommazahlen aus Zeichenketten parsen und generieren. Dieses Dokument schlägt einen Plan vor, um diese Inkonsistenz durch die Bereitstellung und Verwendung von Ersatzfunktionen, die von der Locale unabhängig sind, wo nötig, zu beseitigen.
Einleitung
Python bietet allgemeine Lokalisierungsdienste über das locale-Modul, das unter anderem die Lokalisierung der Anzeige und Konvertierung von numerischen Typen ermöglicht. Locale-Kategorien wie LC_TIME und LC_COLLATE ermöglichen die präzise Konfiguration, welche Aspekte der Anwendung lokalisiert werden sollen.
Die LC_NUMERIC-Kategorie spezifiziert die Formatierung von nicht-monetären numerischen Informationen, wie z. B. des Dezimaltrennzeichens bei Gleitkomma- und Festkommazahlen. Die Lokalisierung der LC_NUMERIC-Kategorie ist derzeit nur im Python-Bereich implementiert; C-Bibliotheken, die von der Python-Laufzeitumgebung aufgerufen werden, sind sich der LC_NUMERIC-Einstellung von Python nicht bewusst. Dies geschieht, um das Verhalten bestimmter Low-Level-Funktionen, die vom Python-Parser und zugehörigem Code verwendet werden, nicht zu ändern [2].
Dies stellt jedoch ein Problem für Erweiterungsmodule dar, die C-Bibliotheken wrappen. Anwendungen, die diese Erweiterungsmodule verwenden, werden Gleitkommazahlen inkonsistent anzeigen und konvertieren.
James Henstridge, der Autor von PyGTK [3], hat zusätzlich darauf hingewiesen, dass die setlocale()-Funktion auch Thread-Sicherheitsprobleme birgt, da ein Thread die C-Bibliotheksfunktion setlocale() außerhalb des GIL aufrufen kann und Python dadurch Gleitkommazahlen falsch parsen und generieren kann.
Begründung
Die Inkonsistenz zwischen Python und der C-Bibliothekslokalisierung für LC_NUMERIC ist ein Problem für jede lokalisierte Anwendung, die C-Erweiterungen verwendet. Die genaue Art des Problems variiert je nach Anwendung, tritt aber höchstwahrscheinlich beim Parsen oder Formatieren von Gleitkommawerten auf.
Beispielproblem
Das ursprüngliche Problem, das diesen PEP motivierte, hängt mit dem GtkSpinButton [4]-Widget im GTK+-UI-Toolkit zusammen, das vom PyGTK-Modul umschlossen wird. Das Widget kann in den numerischen Modus versetzt werden, und wenn dies geschieht, werden eingegebene Zeichen als Zahl ausgewertet.
Probleme treten auf, wenn LC_NUMERIC auf eine Locale gesetzt wird, deren Gleitkommazedentrenner sich vom Standard der C-Locale unterscheidet (z. B. ',' anstelle von '.' für die brasilianische Locale pt_BR). Da LC_NUMERIC nicht auf libc-Ebene gesetzt ist, werden Gleitkommazahlen in der Texteingabe des Spinbuttons falsch angezeigt (mit '.' als Trennzeichen), und es ist unmöglich, gebrochene Werte mit dem ','-Trennzeichen einzugeben.
Dieses kleine Beispiel zeigt eine reduzierte Benutzerfreundlichkeit für lokalisierte Anwendungen, die dieses Toolkit in Python verwenden.
Vorschlag
Martin v. Löwis kommentierte die ursprünglichen Einschränkungen für eine akzeptable Lösung des Problems auf python-dev
LC_NUMERICkann auf C-Bibliotheksebene gesetzt werden, ohne den Parser zu beschädigen.float()undstr()bleiben locale-unabhängig.- Locale-abhängige
str()undatof()verbleiben im locale-Modul.
Eine Analyse des Python-Quellcodes deutet darauf hin, dass die folgenden Funktionen derzeit davon abhängen, dass LC_NUMERIC auf die C-Locale gesetzt ist
Python/compile.c:parsenumber()Python/marshal.c:r_object()Objects/complexobject.c:complex_to_buf()Objects/complexobject.c:complex_subtype_from_string()Objects/floatobject.c:PyFloat_FromString()Objects/floatobject.c:format_float()Objects/stringobject.c:formatfloat()Modules/stropmodule.c:strop_atof()Modules/cPickle.c:load_float()
Der vorgeschlagene Ansatz besteht darin, LC_NUMERIC-unabhängige Funktionen für die Konvertierung von ( strtod()/atof() ) und zu ( snprintf() ) Gleitkommaformaten zu implementieren und diese Funktionen dort zu verwenden, wo die Formatierung nicht von der benutzerspezifischen Locale abweichen soll.
Das locale-Modul sollte ebenfalls geändert werden, um die Sonderbehandlung für LC_NUMERIC zu entfernen.
Diese Änderung sollte auch die oben genannten Thread-Sicherheitsprobleme lösen.
Potenzielle Code-Beiträge
Dieses Problem wurde ursprünglich als Problem in den GTK+-Bibliotheken gemeldet [5]; seitdem wurde es korrekt als Inkonsistenz in Pythons Implementierung diagnostiziert. Zufällig implementiert die glib-Bibliothek (hauptsächlich für GTK+ entwickelt, nicht zu verwechseln mit der GNU C-Bibliothek) eine Reihe von LC_NUMERIC-unabhängigen Funktionen (als Beispiel siehe [6]) aus ähnlichen Gründen wie in diesem Papier dargelegt.
Im selben GTK+-Problembericht schlug Havoc Pennington vor, dass die glib-Autoren bereit wären, diesen Code an die PSF beizutragen, was die Implementierung dieses PEP erheblich vereinfachen würde. Alex Larsson, der ursprüngliche Autor des glib-Codes, reichte eine PSF Contributor Agreement [7] am 20.08.2003 ein [8], um sicherzustellen, dass der Code sicher integriert werden konnte; diese Vereinbarung wurde erhalten und akzeptiert.
Risiken
Es kann plattformübergreifende Probleme mit den bereitgestellten locale-unabhängigen Funktionen geben, obwohl dieses Risiko gering ist, da der bereitgestellte Code lediglich alle von der Locale abhängigen Änderungen an Gleitkommazahlen rückgängig macht.
Martin und Guido wiesen auf potenzielle Urheberrechtsprobleme mit dem beigesteuerten Code hin. Ich glaube, wir werden in diesem Bereich keine Probleme haben, da Mitglieder des GTK+- und glib-Teams gesagt haben, dass sie damit einverstanden sind, den Code neu zu lizenzieren, und ein PSF Contributor Agreement eingereicht wurde, um diese Sicherheit zu gewährleisten.
Tim Peters hat darauf hingewiesen [9], dass es Situationen gibt, die Threads betreffen, in denen die vorgeschlagene Änderung nicht ausreicht, um das Problem vollständig zu lösen. Eine vollständige Lösung existiert derzeit jedoch noch nicht.
Implementierung
Eine Implementierung wurde von Gustavo Carneiro <gjc at inescporto.pt> entwickelt und an Sourceforge.net Bug 774665 angehängt [10]
Der endgültige Patch [11] wurde am 08.06.2004 von Martin v. Löwis in den Python CVS integriert, wie im Bug-Report angegeben.
Referenzen
Urheberrecht
Dieses Dokument wurde gemeinfrei erklärt.
Quelle: https://github.com/python/peps/blob/main/peps/pep-0331.rst
Zuletzt geändert: 2025-02-01 08:59:27 GMT