Domanda

Abbiamo già ottenuto la nostra base di codice in esecuzione su Python 2.6. Per prepararci a Python 3.0, abbiamo iniziato ad aggiungere:

from __future__ import unicode_literals

nei nostri file .py (mentre li modifichiamo). Mi chiedo se qualcun altro lo stia facendo e si sia imbattuto in gotcha non ovvi (forse dopo aver trascorso molto tempo a eseguire il debug).

È stato utile?

Soluzione

La principale fonte di problemi che ho riscontrato lavorando con stringhe unicode è quando mescoli stringhe codificate utf-8 con stringhe unicode.

Ad esempio, considera i seguenti script.

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

L'output dell'esecuzione di python one.py è:

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 questo esempio, two.name è una stringa codificata utf-8 (non unicode) poiché non ha importato unicode_literals e one.name è una stringa unicode. Quando mescoli entrambi, python tenta di decodificare la stringa codificata (supponendo che sia ascii) e convertirla in unicode e fallisce. Funzionerebbe se avessi print name + two.name.decode ('utf-8') .

La stessa cosa può succedere se si codifica una stringa e si tenta di mescolarla in un secondo momento. Ad esempio, funziona:

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

Output:

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

Ma dopo aver aggiunto import unicode_literals NON:

# 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

Output:

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)

Non riesce perché 'DEBUG:% s' è una stringa unicode e quindi Python tenta di decodificare html . Un paio di modi per correggere la stampa sono print str ('DEBUG:% s')% html o print 'DEBUG:% s'% html.decode ('utf-8 ') .

Spero che questo ti aiuti a capire i potenziali gotcha quando si usano stringhe unicode.

Altri suggerimenti

Anche in 2.6 (prima di Python 2.6.5 RC1 +) i letterali unicode non giocano bene con gli argomenti delle parole chiave ( issue4978 ):

Il seguente codice, ad esempio, funziona senza unicode_literals, ma non riesce con TypeError: le parole chiave devono essere stringa se viene utilizzato unicode_literals.

  >>> 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

Ho scoperto che se aggiungi la direttiva unicode_literals dovresti anche aggiungere qualcosa come:

 # -*- coding: utf-8

alla prima o seconda riga il tuo file .py. Altrimenti linee come:

 foo = "barré"

genera un errore come:

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

Prendi anche in considerazione che unicode_literal influenzerà eval () ma non repr () (un comportamento asimmetrico che rappresenta un bug) , ovvero eval (repr (b '\ xa4')) non sarà uguale a b '\ xa4' (come farebbe con Python 3).

Idealmente, il seguente codice sarebbe un invariante, che dovrebbe sempre funzionare, per tutte le combinazioni di unicode_literals e utilizzo di Python {2.7, 3.x}:

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+

La seconda affermazione sembra funzionare, poiché repr ('\ xa4') viene valutato in u '\ xa4' in Python 2.7.

Ce ne sono altri.

Ci sono librerie e builtin che prevedono stringhe che non tollerano l'unicode.

Due esempi:

incorporato:

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

(leggermente esotico) non funziona con unicode_literals: type () prevede una stringa.

biblioteca:

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

non funziona: la libreria wx pubsub prevede un tipo di messaggio stringa.

Il primo è esoterico e facilmente risolvibile con

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

ma quest'ultimo è devastante se il tuo codice è pieno di chiamate a pub.sendMessage () (quale è il mio).

Dang it, eh?!?

Il clic genererà eccezioni unicode in tutto il luogo se qualsiasi modulo che ha da __future__ import unicode_literals viene importato dove si utilizza click.echo . È un incubo ...

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top