101 votes

Des pièges utilisant unicode_literals dans Python 2.6?

Notre base de code fonctionne déjà sous Python 2.6. Afin de préparer Python 3.0, nous avons commencé à ajouter:

depuis __future__ import unicode_literals

dans nos .py fichiers (tels que nous les modifions). Je me demande si quelqu'un d'autre a fait cela et s'est heurté à des pièges non évidents (peut-être après avoir passé beaucoup de temps à déboguer).

101voto

Koba Points 2319

La principale source de problèmes que j'ai eu à travailler avec des chaînes unicode, c'est quand vous mélangez codé en utf-8 avec chaînes unicode.

Considérons, par exemple, les scripts suivants.

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

La sortie de l'exécution de python one.py est:

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)

Dans cet exemple, two.name est codé en utf-8 chaîne (pas unicode), car il n'a pas importer unicode_literals, et one.name est une chaîne unicode. Lorsque vous mélangez les deux, python essaie de décoder la chaîne codée (en supposant que c'est de l'ascii) et de le convertir au format unicode et échoue. Il pourrait fonctionner si vous n'avez print name + two.name.decode('utf-8').

La même chose peut se produire si vous encodez une chaîne et d'essayer de les mélanger plus tard. Par exemple, cela fonctionne:

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

Sortie:

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

Mais après l'ajout de l' import unicode_literals il ne:

# 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

Sortie:

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)

Il échoue en raison d' 'DEBUG: %s' est une chaîne unicode et donc de python essaie de décoder html. Un couple de façons de corriger l'impression sont de le faire) print str('DEBUG: %s') % html ou print 'DEBUG: %s' % html.decode('utf-8').

J'espère que cela vous aide à comprendre le potentiel de pièges courants lors de l'utilisation de chaînes unicode.

16voto

mfazekas Points 3024

De plus, dans la version 2.6 (avant la version 2.6.5 RC1 + de python), les littéraux unicode ne fonctionnent pas bien avec les arguments de mot clé ( issue4978 ):

Le code suivant, par exemple, fonctionne sans unicode_literals, mais échoue avec TypeError: keywords must be string si unicode_literals est utilisé.

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

13voto

Jacob Gabrielson Points 8800

J'ai constaté que si vous ajoutez la directive unicode_literals vous devez également ajouter quelque chose comme:

  # -*- coding: utf-8
 

à la première ou à la deuxième ligne de votre fichier .py. Sinon, des lignes telles que:

  foo = "barré"
 

entraîner une erreur telle que:

SyntaxError: caractère non-ASCII '\ xc3' dans le fichier mumble.py à la ligne 198,
 mais aucun encodage déclaré; voir http://www.python.org/peps/pep-0263.html 
 pour plus de détails

7voto

hvr Points 3850

Aussi prendre en compte qu' unicode_literal affectera eval() mais pas repr() (un comportement asymétrique qui à mon humble avis est un bug), c'est à dire eval(repr(b'\xa4')) ne sera pas égal à b'\xa4' (comme il le ferait avec Python 3).

Idéalement, le code suivant devrait être un invariant, qui devrait toujours fonctionner, pour toutes les combinaisons unicode_literals et Python {2.7, 3.x} utilisation:

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 deuxième assertion se produit au travail, depuis repr('\xa4') évalue u'\xa4' dans Python 2.7.

5voto

GreenAsJade Points 1729

Il y a plus.

Il y a des bibliothèques et des objets internes qui attendent des chaînes qui ne tolèrent pas l'unicode.

Deux exemples:

builtin:

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

(légèrement esotic) ne fonctionne pas avec unicode_literals: type() attend une chaîne de caractères.

bibliothèque:

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

ne fonctionne pas: le wx pubsub bibliothèque attend une chaîne de type de message.

Le premier est ésotérique et facilement résolus grâce à des

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

mais ce dernier est dévastateur si votre code est plein d'appels de pub.sendMessage() (dont la mienne).

Dang, hein?!?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X