Alle Menschen, die sich außerhalb des englischen Sprachraums mit Python beschäftigen, stoßen recht bald auf Zeichenketten, die über die ASCII-Grenzen hinausragen. Python 2.x unterscheidet zwischen Bytestrings (Typ: str
) und Unicode Strings (Typ: unicode
). Letztere bestehen aus einer Kette von Unicode-Zeichen, erstere dagegen aus einer Kette von Bytes, die Unicode-Zeichen in einer bestimmten Kodierung entsprechen (wobei ein Unicode-Zeichen durch ein oder mehrere Bytes repräsentiert werden kann). Der Wechsel zwischen beiden Typen erfolgt über die Methoden encode()
bzw. decode()
:
>>> encoded_string1 = 'Übelkrähe' >>> unicode_object1 = u'Übelkrähe' >>> encoded_string2 = unicode_object1.encode('utf-8') >>> encoded_string1 == encoded_string2 True >>> unicode_object2 = encoded_string1.decode('utf-8') >>> unicode_object1 == unicode_object2 True
Das obige Beispiel funktioniert natürlich nur, wenn das Terminal, in dem Python ausgeführt wird, die Kodierung UTF-8 verwendet. Innerhalb eines Skripts gibt man die Source Code Encoding explizit an:
#!/usr/bin/python # -*- coding: utf-8 -*-
Problematisch wird es, wenn Bytestrings und Unicode Strings ohne explizite Umwandlung kombiniert werden sollen:
>>> template_string = 'Wohlrabe {0}' >>> unicode_object1 = u'Übelkrähe' >>> template_string.format(unicode_object1) Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode character u'\xdc' in position 0: ordinal not in range(128)
Python verwendet für die automatische Umwandlung von Unicode Strings in Bytestrings nämlich die ASCII-Kodierung, die neben dem lateinischen Alphabet nur arabische Ziffern und einige Satz- und Steuerzeichen umfasst. Alle anderen Zeichen führen je nach Lage zu einem UnicodeEncodeError
oder einem UnicodeDecodeError
. Die wichtigste Unicode-Regel lautet deshalb:
Software should only work with Unicode strings internally, converting to a particular encoding on output.
Das impliziert allerdings, dass jeder Unicode String vor der Übergabe an die write()
-Methode einer geöffneten Datei kodiert wird. Andernfalls läuft man wieder in die ASCII-Falle:
>>> output_file = open('output', 'w') >>> output_file.write(unicode_object1) Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode character u'\xdc' in position 0: ordinal not in range(128)
Jedes Unicode-Objekt vor der Ausgabe manuell zu kodieren ist zwar möglich –
>>> output_file.write(unicode_object1.encode('utf-8'))
– aber sehr aufwendig. Glücklicherweise gibt es das Modul codecs
. Die Funktion codecs.open()
-Funktion erlaubt es, beim Öffnen einer Datei die gewünschte (Ausgabe-)Kodierung anzugeben:
>>> import codecs >>> output_file = codecs.open('output', 'w', encoding='utf-8') >>> output_file.write(unicode_object1)
Die Funktion codecs.open()
erweist sich auch beim Lesen von Dateien als hilfreich. Liest man mit der normalen open()
-Funktion aus einer Datei, die Text in der Kodierung Mac OS Roman enthält, so muss der resultierende Bytestring erst manuell in einen Unicode String umgewandelt werden:
>>> file = open('file') >>> content = file.read() >>> type(content) <type 'str'> >>> print content ?belkr?he >>> unicode_content = content.decode('macroman') >>> type(unicode_content) <type 'unicode'> >>> print unicode_content Übelkrähe
Öffnet man dieselbe Datei dagegen mit codecs.open()
und dem passenden encoding
-Parameter, liefert die read()
-Methode automatisch einen Unicode String:
>>> import codecs >>> file = codecs.open('file', encoding='macroman') >>> content = file.read() >>> type(content) <type 'unicode'> >>> print content Übelkrähe
Leider ist dieses Wissen (wie immer) schon beim Erwerb veraltet: In Python 3 sind Unicode Strings (Class: str
) der Normalfall und Bytestrings (Class: bytes
) die explizit zu deklarierende Ausnahme:
>>> unicode_string = 'This is a unicode string' >>> type(unicode_string) <class 'str'> >>> byte_string = b'This is a bytestring' >>> type(byte_string) <class 'bytes'>
Die generische Funktion open()
verfügt in Python 3 über einen encoding
-Parameter (so dass das codecs
-Modul nur für Spezialfälle wie die Implementierung neuer Kodierungen benötigt wird), und selbst auf die Angabe der Source Code Encoding kann man in der Regel verzichten: Python 3 unterstellt nicht mehr ASCII, sondern UTF-8. Sobald alle relevanten Pakete angepasst wurden, steht der schönen neuen Welt nichts mehr im Weg.
Update: Ich sollte aufhören, technische Sachverhalte umständlich zu beschreiben. Fünf Minuten nach Fertigstellung dieses Eintrags habe ich eine zwei Jahre alte Präsentation entdeckt (sowie eine deutsche Übersetzung), die mit meinen Ausführungen nahezu identisch ist.