Quaisquer gotchas usando unicode_literals em Python 2.6?
-
03-07-2019 - |
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).
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 ...