La principale source de problèmes que j'ai rencontrés en travaillant avec des chaînes Unicode est lorsque vous mélangez des chaînes encodées en utf-8 avec des chaînes Unicode.
Par exemple, considérez 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
Le résultat de l'exécution 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 encodée en utf-8 (pas unicode) car elle n'a pas été importée 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 qu'elle est ascii) et de la convertir en Unicode et échoue. Cela fonctionnerait si vous le faisiez print name + two.name.decode('utf-8')
.
La même chose peut arriver si vous encodez une chaîne et essayez 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
Production:
DEBUG: <html><body>helló wörld</body></html>
Mais après avoir ajouté le, import unicode_literals
il ne fait 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
Production:
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 il 'DEBUG: %s'
s'agit d'une chaîne Unicode et par conséquent, python essaie de décoder html
. Deux façons de corriger l'impression sont soit de faire 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 lors de l'utilisation de chaînes Unicode.
decode()
solutions au lieu des solutionsstr()
ouencode()
: plus vous utilisez souvent des objets Unicode, plus le code est clair, car ce que vous voulez, c'est manipuler des chaînes de caractères, pas des tableaux d'octets avec un encodage implicite externe.when you mix utf-8 encoded strings with unicode ones
UTF-8 et Unicode et pas 2 encodages différents; Unicode est un standard et UTF-8 est l'un des encodages qu'il définit.str
, le second est de typeunicode
. Étant des objets différents, un problème peut survenir si vous essayez de les additionner / concaténer / interpolerpython>=2.6
oupython==2.6
?Aussi dans 2.6 (avant python 2.6.5 RC1 +) 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é.la source
J'ai trouvé que si vous ajoutez la
unicode_literals
directive, vous devriez également ajouter quelque chose comme:à la première ou à la deuxième ligne de votre fichier .py. Sinon, des lignes telles que:
entraîner une erreur telle que:
la source
# -*- coding: utf-8
est une déclaration pratiquement obligatoire, que vous l'unicode_literals
-*-
n'est pas obligatoire; si vous optez pour la méthode compatible emacs, je pense que vous en auriez besoin-*- encoding: utf-8 -*-
(voir aussi-*-
à la fin). Tout ce dont vous avez besoin estcoding: utf-8
(ou même à la=
place de:
).from __future__ import unicode_literals
.# -*- coding: utf-8 -*-
"codage" (pas le "codage" ou le "codage de fichier" ou quoi que ce soit d'autre - Python recherche simplement le "codage" quel que soit le préfixe).Tenez également compte de ce
unicode_literal
qui affecteraeval()
mais pasrepr()
(un comportement asymétrique qui à mon avis est un bug), c'est-à-direeval(repr(b'\xa4'))
ne sera pas égal àb'\xa4'
(comme ce serait le cas avec Python 3).Idéalement, le code suivant serait un invariant, qui devrait toujours fonctionner, pour toutes les combinaisons d'utilisation de
unicode_literals
Python {2.7, 3.x}:La deuxième assertion fonctionne, puisqu'elle est
repr('\xa4')
évaluéeu'\xa4'
en Python 2.7.la source
repr
pour régénérer un objet. Larepr
documentation indique clairement que ce n'est pas une exigence. À mon avis, cela relèguerepr
à quelque chose d'utile uniquement pour le débogage.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é:
(légèrement ésotique) ne fonctionne pas avec unicode_literals: type () attend une chaîne.
bibliothèque:
ne fonctionne pas: la bibliothèque wx pubsub attend un type de message string.
Le premier est ésotérique et se fixe facilement avec
mais ce dernier est dévastateur si votre code est plein d'appels à pub.sendMessage () (ce qui est le mien).
Dang, hein?!?
la source
class Meta:
devraient êtreb'field_name'
Cliquez sur déclenchera des exceptions Unicode partout si un module qui a
from __future__ import unicode_literals
été importé là où vous l'utilisezclick.echo
. C'est un cauchemar…la source