Question

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

from __future__ import unicode_literals

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

Était-ce utile?

La solution

La principale source de problèmes que j'ai rencontrés lors de l'utilisation de chaînes unicode provient du mélange de chaînes encodées en utf-8 avec des chaînes unicode.

Par exemple, considérez les scripts suivants.

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

Le résultat 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 une chaîne codée en utf-8 (non unicode) car elle n'a pas importé 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 ce soit ascii) et la convertit en unicode et échoue. Cela fonctionnerait si vous imprimiez nom + deux.nom.decode ('utf-8') .

La même chose peut se produire si vous encodez une chaîne et essayez de la 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 avoir ajouté le import unicode_literals , cela ne signifie PAS:

# 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 car 'DEBUG:% s' est une chaîne unicode et que, par conséquent, python tente de décoder html . Voici deux manières de corriger l'impression: print str ('DEBUG:% s')% html ou print 'DEBUG:% s'% html.decode ('utf-8 ') .

J'espère que cela vous aidera à comprendre les pièges potentiels liés à l'utilisation de chaînes Unicode.

Autres conseils

Également dans la version 2.6 (avant python 2.6.5 RC1 +), les littéraux unicode ne fonctionnent pas bien avec les arguments de mots clés ( issue4978 ):

Le code suivant, par exemple, fonctionne sans unicode_literals, mais échoue avec TypeError: les mots clés doivent être chaîne 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

J'ai constaté que si vous ajoutez la directive unicode_literals , vous devez également ajouter un élément tel que:

 # -*- coding: utf-8

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

 foo = "barré"

entraîne une erreur telle que:

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

Tenez également compte du fait que unicode_literal affectera eval () mais pas repr () (comportement asymétrique qui imho est un bogue). eval (repr (b '\ xa4')) ne sera pas égal à b '\ xa4' (comme avec Python 3).

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

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 fonctionne, car repr ('\ xa4') est évalué à u '\ xa4' dans Python 2.7.

Il y en a plus.

Il existe des bibliothèques et des fonctions intégrées qui attendent des chaînes qui ne tolèrent pas l’unicode.

Deux exemples:

intégré:

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

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

bibliothèque:

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

ne fonctionne pas: la bibliothèque wx pubsub attend un type de message sous forme de chaîne.

Le premier est ésotérique et facile à corriger avec

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

mais ce dernier est dévastateur si votre code est plein d’appels à pub.sendMessage () (quel mien est).

Dang, hein?!?

Click soulève des exceptions unicode partout si un module comportant de __future__ import unicode_literals est importé et que vous utilisez click.echo . C'est un cauchemar & # 8230;

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top