Warum Unicode () verwendet str () auf meinem Objekt nur mit keiner Codierung gegeben?
Frage
Ich beginne mit einem String-Variable mit einigen Nicht-ascii Erstellen utf-8 codierte Daten über sie:
>>> text = 'á'
>>> text
'\xc3\xa1'
>>> text.decode('utf-8')
u'\xe1'
Mit unicode()
auf sie Fehler wirft ...
>>> unicode(text)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0:
ordinal not in range(128)
... aber wenn ich die Codierung weiß, ich kann es als zweiten Parameter verwenden:
>>> unicode(text, 'utf-8')
u'\xe1'
>>> unicode(text, 'utf-8') == text.decode('utf-8')
True
Nun, wenn ich eine Klasse, die diesen Text in der __str__()
Methode gibt:
>>> class ReturnsEncoded(object):
... def __str__(self):
... return text
...
>>> r = ReturnsEncoded()
>>> str(r)
'\xc3\xa1'
unicode(r)
scheint str()
auf, es zu benutzen, da sie die gleichen Fehler wie unicode(text)
oben aufwirft:
>>> unicode(r)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0:
ordinal not in range(128)
Bis jetzt ist alles wie geplant!
Aber wie würde niemand jemals erwarten, unicode(r, 'utf-8')
nicht einmal versuchen:
>>> unicode(r, 'utf-8')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: coercing to Unicode: need string or buffer, ReturnsEncoded found
Warum? Warum dies inkonsistentes Verhalten? Ist es ein Fehler? ist beabsichtigt? Sehr umständlich.
Lösung
Das Verhalten scheint verwirrend, aber intensionalen. Ich gebe hier die Gesamtheit der Unicode-Dokumentation aus dem Python Integrierte Funktionen Dokumentation (für Version 2.5.2, da ich dies schreibe):
Unicode ([object [, Kodierung [Fehler]]])
Gibt die Unicode-String-Version des Objekts eine der folgenden Modi:
Wenn Codierung und / oder Fehler gegeben, Unicode () dekodiert die Gegenstand, der entweder ein 8-Bit-String oder ein Zeichenpuffer sein kann, Verwendung der Codec für die Codierung. Die Kodierungsparameter ist ein String geben den Namen eines Codiersystems; wenn die Kodierung nicht bekannt ist, LookupError angehoben. Die Fehlerbehandlung wird nach getan Fehler; Dies gibt die Behandlung von Zeichen, die invalid im Eingangscodierung. Wenn Fehler ist ‚strenge‘ (das Standard), wird ein Valueerror auf Fehler angehoben, während ein Wert von ‚Ignore‘ verursacht Fehler stillschweigend ignoriert werden, und ein Wert von ‚Ersetzen‘ bewirkt, dass die offiziellen Unicode-Ersatzzeichen, U + FFFD, werden verwendet, um Eingangszeichen zu ersetzen, die nicht sein kann decodiert. Siehe auch die Codecs Modul.
Wenn keine optionalen Parameter angegeben werden, Unicode () wird imitieren die Verhalten von str (), außer dass es gibt Unicode-Strings anstelle von 8-Bit-Strings. Genauer gesagt, wenn das Objekt eine Unicode ist String oder Unterklasse wird es, dass Unicode-String zurück, ohne Jede zusätzliche Decodierung angewendet.
Für Objekte, die einen __unicode __ () -Methode zur Verfügung stellen, wird es nennen diese Methode ohne Argumente eine Unicode-Zeichenfolge zu erstellen. Zum alle anderen Objekte, die 8-Bit-String-Version oder Darstellung angefordert und dann in einen Unicode-String konvertiert den Codec für die Standard-Kodierung in ‚strenge‘ Modus.
Neu in der Version 2.0. Geändert in Version 2.2: Unterstützung für __unicode __ () hinzugefügt.
Wenn Sie also unicode(r, 'utf-8')
nennen, erfordert es einen 8-Bit-String oder einen Zeichenpuffer als erstes Argument, so dass es nötigt Ihr Objekt der __str__()
Methode verwendet, und versucht zu entschlüsseln, dass die utf-8
Codec. Ohne den utf-8
sieht die unicode()
Funktion für ein für eine __unicode__()
Methode auf dem Objekt, und findet es nicht, ruft die __str__()
Methode, wie Sie vorgeschlagen, zu versuchen, die Standard-Codec zu verwenden, um Unicode zu konvertieren.
Andere Tipps
unicode
erraten nicht die Codierung Ihres Textes. Wenn Ihr Objekt selbst als unicode
drucken können, definieren die __unicode__()
Methode, die eine Unicode-Zeichenfolge zurückgibt.
Das Geheimnis ist, dass unicode(r)
nicht tatsächlich __str__()
selbst aufrufen. Stattdessen sieht es für eine __unicode__()
Methode. Die Standardimplementierung von __unicode__()
wird __str__()
aufrufen und dann sie zu entschlüsseln versuchen, die ascii
charset verwenden. Wenn Sie die Codierung übergeben, erwartet unicode()
das erste Objekt etwas sein, das decodiert werden kann -. Das heißt, eine Instanz von basestring
Das Verhalten ist seltsam, weil es versucht, als ascii zu dekodieren, wenn ich nicht passieren ‚utf-8‘. Aber wenn ich 'utf-8' Pass gibt es einen anderen Fehler ...
Das ist, weil, wenn Sie „utf-8“ angeben, ist es den ersten Parameter behandelt, als ein strangartige Objekt decodiert werden. Ohne sie, es behandelt die Parameter als ein Objekt zu Unicode gezwungen werden.
Ich verstehe nicht, die Verwirrung. Wenn Sie wissen, dass das text
Attribut des Objekts wird immer UTF-8 kodiert sein, nur __unicode__()
definieren und dann wird alles gut funktionieren.