Frage

Wir haben bereits unsere Code-Basis bekommen unter Python läuft 2.6. Um für Python vorzubereiten 3.0, haben wir begonnen, und fügte hinzu:

from __future__ import unicode_literals

in unsere .py Dateien (wie wir sie ändern). Ich frage mich, ob jemand hat dies getan und hat sich in allen nicht-offensichtliche gotchas laufen (vielleicht nach viel Zeit Debugging Ausgaben).

War es hilfreich?

Lösung

Die Hauptquelle der Probleme, die ich mit Unicode-Strings arbeiten habe ist, wenn Sie utf-8 kodierten Strings mit Unicode diejenigen mischen.

Betrachten wir zum Beispiel die folgenden Skripte.

two.py

# encoding: utf-8
name = 'helló wörld from two'

one.py

# encoding: utf-8
from __future__ import unicode_literals
import two
name = 'helló wörld from one'
print name + two.name

Der Ausgang python one.py des Laufens ist:

Traceback (most recent call last):
  File "one.py", line 5, in <module>
    print name + two.name
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 4: ordinal not in range(128)

In diesem Beispiel two.name ist ein utf-8 kodierten String (nicht Unicode), da es nicht unicode_literals importiert wurde, und one.name ist ein Unicode-String. Wenn Sie beide mischen, Python die codierte Zeichenfolge zu entschlüsseln versucht (vorausgesetzt, es ist ascii) und es in Unicode konvertieren und schlägt fehl. Es würde funktionieren, wenn Sie print name + two.name.decode('utf-8') getan hat.

Das gleiche kann passieren, wenn Sie eine Zeichenfolge kodieren und versuchen, sie später zu mischen. Zum Beispiel, das funktioniert:

# encoding: utf-8
html = '<html><body>helló wörld</body></html>'
if isinstance(html, unicode):
    html = html.encode('utf-8')
print 'DEBUG: %s' % html

Ausgabe:

DEBUG: <html><body>helló wörld</body></html>

Aber nach dem import unicode_literals Hinzufügen es nicht:

# encoding: utf-8
from __future__ import unicode_literals
html = '<html><body>helló wörld</body></html>'
if isinstance(html, unicode):
    html = html.encode('utf-8')
print 'DEBUG: %s' % html

Ausgabe:

Traceback (most recent call last):
  File "test.py", line 6, in <module>
    print 'DEBUG: %s' % html
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 16: ordinal not in range(128)

Es schlägt fehl, weil 'DEBUG: %s' ein Unicode-String ist und daher Python versucht html zu entschlüsseln. Ein paar Möglichkeiten, um den Druck zu beheben sind entweder print str('DEBUG: %s') % html oder print 'DEBUG: %s' % html.decode('utf-8') tun.

Ich hoffe, das hilft Ihnen dabei, das Potential gotchas verstehen, wenn Unicode-Strings verwendet wird.

Andere Tipps

Auch in 2,6 (vor Python 2.6.5 RC1 +) Unicode-Literale mit Keyword-Argumenten nicht schön spielen ( issue4978 ):

Der folgende Code beispielsweise arbeitet ohne unicode_literals, doch irgendwie Typeerror: keywords must be string wenn unicode_literals verwendet wird

.
  >>> def foo(a=None): pass
  ...
  >>> foo(**{'a':1})
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
      TypeError: foo() keywords must be strings

Ich fand, dass, wenn Sie die unicode_literals Richtlinie hinzufügen, sollten Sie auch so etwas wie hinzufügen:

 # -*- coding: utf-8

auf den ersten oder zweiten Zeile Ihre .py-Datei. Ansonsten Zeilen wie:

 foo = "barré"

Ergebnis in einem ein Fehler wie zum Beispiel:

SyntaxError: Non-ASCII character '\xc3' in file mumble.py on line 198,
 but no encoding declared; see http://www.python.org/peps/pep-0263.html 
 for details

Nehmen Sie auch zu berücksichtigen, die beeinflussen unicode_literal eval() aber nicht repr() (ein asymmetrisches Verhalten, das imho ein Fehler ist), das heißt eval(repr(b'\xa4')) wird b'\xa4' nicht gleich sein (wie wäre es mit Python 3).

Idealerweise würde der folgende Code eine invariant sein, die für alle Kombinationen von unicode_literals und Python immer, sollte {2.7, 3.x} Nutzung:

from __future__ import unicode_literals

bstr = b'\xa4'
assert eval(repr(bstr)) == bstr # fails in Python 2.7, holds in 3.1+

ustr = '\xa4'
assert eval(repr(ustr)) == ustr # holds in Python 2.7 and 3.1+

Die zweite Behauptung geschieht, zu arbeiten, da repr('\xa4') in Python 2.7 u'\xa4' auswertet.

Es gibt mehr.

Es gibt Bibliotheken und builtins, die Strings erwarten, die Unicode nicht tolerieren.

Zwei Beispiele:

builtin:

myenum = type('Enum', (), enum)

(leicht esotic) funktioniert nicht mit unicode_literals:. Typ () erwartet einen String

Bibliothek:

from wx.lib.pubsub import pub
pub.sendMessage("LOG MESSAGE", msg="no go for unicode literals")

funktioniert nicht:. Die wx PubSub Bibliothek erwartet einen String Nachrichtentyp

Das erstere ist esoterisch und leicht behoben mit

myenum = type(b'Enum', (), enum)

aber letztere ist verheerend, wenn Ihr Code voller Anrufe pub.sendMessage ist () (die Mine).

Dang es, was?!?

erhöhen wird Klicken Sie auf Unicode Ausnahmen alle über den Ort wenn jedes Modul, das from __future__ import unicode_literals hat importiert, wo Sie click.echo verwenden. Es ist ein Albtraum ...

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top