Question

Je commence par créer une variable chaîne contenant des données non ASCII utf-8 :

>>> text = 'á'
>>> text
'\xc3\xa1'
>>> text.decode('utf-8')
u'\xe1'

L'utilisation de unicode () soulève des erreurs ...

>>> unicode(text)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: 
                    ordinal not in range(128)

... mais si je connais l'encodage, je peux l'utiliser comme second paramètre:

>>> unicode(text, 'utf-8')
u'\xe1'
>>> unicode(text, 'utf-8') == text.decode('utf-8')
True

Maintenant, si j'ai une classe qui retourne ce texte dans la méthode __ str __ () :

>>> class ReturnsEncoded(object):
...     def __str__(self):
...         return text
... 
>>> r = ReturnsEncoded()
>>> str(r)
'\xc3\xa1'

unicode (r) semble utiliser str () , car il génère la même erreur que unicode (texte) ci-dessus:

>>> unicode(r)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: 
                    ordinal not in range(128)

Jusqu'à présent, tout se passe comme prévu!

Mais comme personne ne s'y attendrait, unicode (r, 'utf-8') n'essaiera même pas:

>>> unicode(r, 'utf-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: coercing to Unicode: need string or buffer, ReturnsEncoded found

Pourquoi? Pourquoi ce comportement incohérent? Est-ce un bug? est-ce prévu? Très gênant.

Était-ce utile?

La solution

Le comportement semble déroutant, mais intensionnel. Je reproduis ici l'intégralité de la documentation unicode de la documentation sur les fonctions intégrées Python (pour la version 2.5.2, au moment où j'écris ceci):

  

unicode ([objet [, encodage [, erreurs]]])

     

Renvoyez la version chaîne Unicode de l'objet en utilisant l'un des modes suivants:

     

Si un codage et / ou des erreurs sont générés, unicode () décodera le      objet qui peut être une chaîne de 8 bits ou un tampon de caractères      en utilisant le codec pour le codage. Le paramètre d'encodage est une chaîne      donner le nom d'un encodage; si le codage n'est pas connu,      LookupError est déclenché. La gestion des erreurs est effectuée conformément à      les erreurs; cela spécifie le traitement des caractères qui sont      invalide dans le codage d'entrée. Si les erreurs sont «strictes» (le      par défaut), une valeur ValueError est générée en cas d'erreur, tandis qu'une valeur de      'ignorer' fait en sorte que les erreurs soient ignorées en silence et qu'une valeur de      'replace' provoque le caractère de remplacement officiel Unicode,      U + FFFD, à utiliser pour remplacer les caractères saisis qui ne peuvent pas être      décodé. Voir aussi le module codecs .

     

Si aucun paramètre optionnel n'est donné, unicode () imitera le      comportement de str () sauf qu'il renvoie des chaînes Unicode      au lieu de chaînes de 8 bits. Plus précisément, si l'objet est un Unicode      chaîne ou sous-classe, il retournera cette chaîne Unicode sans      tout décodage supplémentaire appliqué.

     

Pour les objets qui fournissent une méthode __unicode __ (), il appellera      cette méthode sans arguments pour créer une chaîne Unicode. Pour      tous les autres objets, la version ou la représentation sous forme de chaîne 8 bits est      demandé puis converti en chaîne Unicode à l'aide du codec      pour le codage par défaut en mode 'strict'.

     

Nouveau dans la version 2.0. Modifié dans la version 2.2: Prise en charge de __unicode __ () ajoutée.

Ainsi, lorsque vous appelez unicode (r, 'utf-8') , il nécessite une chaîne de 8 bits ou un tampon de caractères comme premier argument. Par conséquent, il force votre objet à l'aide du < code> __ str __ () et tente de le décoder à l'aide du codec utf-8 . Sans le utf-8 , la fonction unicode () recherche une méthode pour __ unicode __ () sur votre objet et ne le trouve pas. appelle la méthode __ str __ () , comme vous l'avez suggéré, en essayant d'utiliser le codec par défaut pour la conversion en unicode.

Autres conseils

unicode ne devine pas le codage de votre texte. Si votre objet peut s’imprimer lui-même en tant que unicode , définissez la méthode __ unicode __ () qui renvoie une chaîne Unicode.

Le secret est que unicode (r) n'appelle pas réellement __ str __ () . Au lieu de cela, il recherche une méthode __ unicode __ () . L'implémentation par défaut de __ unicode __ () appellera __ str __ () , puis tentera de le décoder à l'aide du jeu de caractères ascii . Lorsque vous transmettez le codage, unicode () s'attend à ce que le premier objet puisse être décodé - c'est-à-dire une instance de basestring .

  

Le comportement est étrange car il essaie de se décoder en ascii si je ne passe pas le mot "utf-8". Mais si je passe 'utf-8', cela donne une erreur différente ...

En effet, lorsque vous spécifiez "utf-8", le premier paramètre est traité comme un objet de type chaîne à décoder. Sans ce paramètre, le paramètre est traité comme un objet à forcer à unicode.

Je ne comprends pas la confusion. Si vous savez que l'attribut text de l'objet sera toujours codé en UTF-8, définissez simplement __ unicode __ () , puis tout fonctionnera correctement.

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