Le problème est que vous appelez encode
sur une str
objet.
Une str
est une chaîne d'octets, représentant généralement du texte codé d'une manière ou d'une autre comme UTF-8. Lorsque vous appelez encode
sur ce point, il doit d'abord être décodé en texte, afin que le texte puisse être réencodé. Par défaut, Python le fait en appelant s.decode(sys.getgetdefaultencoding())
, et getdefaultencoding()
renvoie généralement 'ascii'
.
Donc, vous parlez de texte encodé en UTF-8, en le décodant comme s'il s'agissait d'ASCII, puis en le réencodant en UTF-8.
La solution générale consiste à appeler explicitement decode
avec le bon encodage, au lieu de laisser Python utiliser la valeur par défaut, puis encode
le résultat.
Mais lorsque le bon encodage est déjà celui que vous voulez, la solution la plus simple est de simplement ignorer le .decode('utf-8').encode('utf-8')
et utilisez simplement l'UTF-8 str
comme UTF-8 str
qu'il l'est déjà.
Ou, alternativement, si votre wrapper MySQL a une fonctionnalité pour vous permettre de spécifier un encodage et de récupérer unicode
valeurs pour CHAR
/VARCHAR
/TEXT
colonnes au lieu de str
valeurs (par exemple, dans MySQLdb, vous passez use_unicode=True
au connect
appel, ou charset='UTF-8'
si votre base de données est trop ancienne pour la détecter automatiquement), faites-le. Ensuite, vous aurez unicode
objets, et vous pouvez appeler .encode('utf-8')
sur eux.
En général, la meilleure façon de traiter les problèmes Unicode est la dernière :tout décoder le plus tôt possible, effectuer tout le traitement en Unicode, puis encoder le plus tard possible. Mais dans tous les cas, il faut être cohérent. N'appelez pas str
sur quelque chose qui pourrait être un unicode
; ne pas concaténer un str
littéral à un unicode
ou passez-en un à son replace
méthode; etc. Chaque fois que vous mélangez et faites correspondre, Python va implicitement convertir pour vous, en utilisant votre encodage par défaut, qui n'est presque jamais ce que vous voulez.
En passant, c'est l'une des nombreuses choses avec lesquelles les changements Unicode de Python 3.x aident. Tout d'abord, str
est maintenant du texte Unicode, et non des octets codés. Plus important encore, si vous avez octets codés, par exemple, dans un bytes
objet, appelant encode
vous donnera une AttributeError
au lieu d'essayer de décoder silencieusement afin qu'il puisse ré-encoder. Et, de la même manière, essayer de mélanger et de faire correspondre Unicode et des octets vous donnera une évidente TypeError
, au lieu d'une conversion implicite qui réussit dans certains cas et donne un message crypté sur un encodage ou un décodage que vous n'avez pas demandé dans d'autres.