Pergunta

Nós já chegou nossa base de correr código sob Python 2.6. A fim de se preparar para Python 3.0, que já começaram a adicionar:

from __future__ import unicode_literals

em nossos arquivos .py (como modificá-los). Eu estou querendo saber se alguém tem feito isso e foi executado em alguma dicas não-óbvias (talvez depois de passar um monte de tempo de depuração).

Foi útil?

Solução

A principal fonte de problemas que eu tinha que trabalham com strings unicode é quando você mistura utf-8 cordas codificados com os unicode.

Por exemplo, considere os seguintes scripts.

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

A saída de correr 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)

Neste exemplo, two.name é uma string codificado utf-8 (não unicode) uma vez que não fez unicode_literals importação, e one.name é uma seqüência de caracteres Unicode. Quando você mistura os dois, python tenta decodificar a seqüência codificada (assumindo que é ascii) e convertê-lo para unicode e falha. Ele iria trabalhar se você fez print name + two.name.decode('utf-8').

A mesma coisa pode acontecer se você codificar uma corda e tentar misturá-los mais tarde. Por exemplo, isso funciona:

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

Mas depois de adicionar o import unicode_literals ele não:

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

Ele falha porque 'DEBUG: %s' é uma seqüência de caracteres Unicode e, portanto, tentativas Python para html decodificação. Um par de maneiras de corrigir a impressão ou estão fazendo print str('DEBUG: %s') % html ou print 'DEBUG: %s' % html.decode('utf-8').

Espero que isso ajude você a entender as armadilhas potenciais ao usar strings unicode.

Outras dicas

Também em 2,6 (antes Python 2.6.5 RC1 +) literais Unicode não jogar bonito com argumentos nomeados ( issue4978 ):

O código a seguir, por exemplo, funciona sem unicode_literals, mas falha com TypeError:. keywords must be string se unicode_literals é usado

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

Eu achei que se você adicionar a directiva unicode_literals você também deve adicionar algo como:

 # -*- coding: utf-8

para a primeira ou segunda linha de seu arquivo .py. Caso contrário, linhas, tais como:

 foo = "barré"

resultam em um erro como:

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

também ter em conta que unicode_literal afectará eval() mas não repr() (um comportamento assimétrico que imho é um bug), isto é eval(repr(b'\xa4')) não será igual à b'\xa4' (como seria com o Python 3).

O ideal é que o código a seguir seria uma invariante, que deve sempre trabalhar, para todas as combinações de unicode_literals e Python {2.7, 3.x} Uso:

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+

A segunda afirmação acontece de trabalho, uma vez que avalia repr('\xa4') para u'\xa4' em Python 2.7.

Há mais.

Existem bibliotecas e builtins que esperam cordas que não toleram unicode.

Dois exemplos:

builtin:

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

(ligeiramente esotic) não funciona com unicode_literals:. Tipo () espera uma string

biblioteca:

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

não funciona:. A biblioteca wx pubsub espera um tipo string mensagem

O primeiro é esotérico e facilmente corrigido com

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

mas o último é devastador se o seu código é cheio de chamadas para pub.sendMessage () (que o meu é).

Dang-lo, hein?!?

Clique irão gerar exceções unicode em todo o lugar se qualquer módulo que tem from __future__ import unicode_literals é importado onde você usa click.echo. É um pesadelo ...

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top