web-dev-qa-db-fra.com

(erreur unicode) le codec 'unicodeescape' ne peut pas décoder d'octets - chaîne avec '\ u'

En écrivant mon code pour Python 2.6, mais en pensant à Python 3, j’ai pensé que c’était une bonne idée de mettre

from __future__ import unicode_literals

au sommet de certains modules. En d'autres termes, je demande des ennuis (pour les éviter à l'avenir), mais il se peut que je manque quelques connaissances importantes ici. Je veux pouvoir passer une chaîne représentant un chemin de fichier et instancier un objet aussi simple que 

MyObject('H:\unittests')

Dans Python 2.6, cela fonctionne très bien, pas besoin d’utiliser des doubles barres obliques inverses ou une chaîne brute, même pour un répertoire commençant par '\u..', ce qui est exactement ce que je veux. Dans la méthode __init__, je m'assure que toutes les occurrences uniques \ sont interprétées comme '\\', y compris celles précédant les caractères spéciaux comme dans \a, \b, \f, \n, \r, \t et \v (seul \x reste un problème). Décoder également la chaîne donnée en unicode à l'aide d'un codage (local) fonctionne comme prévu.

Se préparer pour Python 3.xEn simulant mon problème actuel dans un éditeur (à partir d’une console vierge dans Python 2.6), il se passe ce qui suit:

>>> '\u'
'\\u'
>>> r'\u'
'\\u'

(OK jusqu'à ici: '\u' est codé par la console en utilisant le codage local) 

>>> from __future__ import unicode_literals
>>> '\u'
SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 0-1: end of string in escape sequence

En d'autres termes, la chaîne (unicode) n'est pas du tout interprétée comme unicode et n'est pas décodée automatiquement avec le codage local. Néanmoins, pour une chaîne brute:

>>> r'\u'
SyntaxError: (unicode error) 'rawunicodeescape' codec can't decode bytes in position 0-1: truncated \uXXXX

idem pour u'\u':

>>> u'\u'
SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 0-1: end of string in escape sequence

De plus, je m'attendrais à ce que isinstance(str(''), unicode) renvoie True (ce qui n'est pas le cas), car l'importation d'unligne_literals devrait rendre tous les types de chaînes unicode. (modifier:) Parce que dans Python 3, toutes les chaînes sont des séquences de caractères Unicode , je suppose que str('')) retournera une telle chaîne-unicode et que type(str('')) sera à la fois <type 'unicode'> et <type 'str'> (car toutes les chaînes sont unicode), mais réalisent également que <type 'unicode'> is not <type 'str'> . Confusion tout autour ...

Des questions

  • comment puis-je mieux passer les chaînes contenant '\u'? (sans écrire '\\u')
  • from __future__ import unicode_literals implémente-t-il réellement toutes les modifications unicode liées à Python 3. afin que je reçoive un environnement complet de chaînes Python 3?

edit: En Python 3, <type 'str'> est un objet Unicode et <type 'unicode'> n'existe tout simplement pas. Dans mon cas, je veux écrire du code pour Python 2(.6) qui fonctionnera sous Python 3. Mais lorsque je import unicode_literals, je ne peux pas vérifier si une chaîne est de <type 'unicode'> car:

  • Je suppose que unicode ne fait pas partie de l'espace de noms
  • si unicode fait partie de l'espace de noms, un littéral de <type 'str'> est toujours unicode lorsqu'il est créé dans le même module
  • type(mystring) retournera toujours <type 'str'> pour les littéraux unicode dans Python 3

Mes modules sont encodés dans 'utf-8' par un commentaire # coding: UTF-8 en haut, alors que mon locale.getdefaultlocale()[1] renvoie 'cp1252'. Donc, si j'appelle MyObject('çça') depuis ma console, il est codé comme «cp1252» dans Python 2 et dans «utf-8» lors de l'appel de MyObject('çça') à partir du module. En Python 3, il ne sera pas codé, mais littéral unicode.

modifier:

J'ai abandonné tout espoir de pouvoir éviter d'utiliser '\' avant une u (ou x d'ailleurs). De plus, je comprends les limites de l’importation de unicode_literals. Cependant, les nombreuses combinaisons possibles consistant à passer une chaîne d'un module à la console et à inverser vica avec chaque encodage différent, et en plus d'importer unicode_literals ou non et Python 2 vs Python 3, m'ont donné envie de créer une vue d'ensemble en testant réellement . D'où le tableau ci-dessous. enter image description here

En d'autres termes, type(str('')) ne renvoie pas <type 'str'> en Python 3, mais <class 'str'> et tous les problèmes de Python 2 semblent être évités. 

22
Remi

Si je comprends bien, tout ce que from __future__ import unicode_literals fait, c'est de créer tous les littéraux de chaîne de type unicode, au lieu de type de chaîne. C'est:

>>> type('')
<type 'str'>
>>> from __future__ import unicode_literals
>>> type('')
<type 'unicode'>

Mais str et unicode sont toujours des types différents et se comportent exactement comme avant.

>>> type(str(''))
<type 'str'>

Toujours, est de type str.

En ce qui concerne votre problème r'\u', il est inhérent à la conception, car il équivaut à ru '\ u' sans unicode_literals. De la docs:

Lorsqu'un préfixe "r" ou "R" est utilisé conjointement avec un préfixe "u" ou "U", les séquences d'échappement\uXXXX et\UXXXXXXXX sont traitées alors que toutes les autres barres obliques inverses sont laissées dans la chaîne.

Probablement de la manière dont l'analyseur lexical a fonctionné dans la série python2. En python3, cela fonctionne comme vous le souhaiteriez.

Vous pouvez taper la barre oblique inverse deux fois, puis le \u ne sera pas interprété, mais vous obtiendrez deux barres obliques inverses!

Les barres obliques inverses peuvent être masquées avec une barre oblique inverse précédente. cependant, les deux restent dans la chaîne

>>> ur'\\u'
u'\\\\u'

Donc, à mon humble avis, vous avez deux options simples:

  • N'utilisez pas de chaînes brutes et échappez vos barres obliques inverses (compatibles avec python3):

    'H:\\unittests'

  • Soyez trop intelligent et tirez parti des points de code Unicode ( pas compatibles avec python3):

    r'H:\u005cunittests'

16
rodrigo

Pour moi, ce problème était lié à la version non à jour, dans ce cas numpy

Pour réparer: 

conda install -f numpy
0
blue-sky