Depuis le shell Python 2.6:
>>> import sys
>>> print sys.getdefaultencoding()
ascii
>>> print u'\xe9'
é
>>>
Je m'attendais à avoir du charabia ou une erreur après l'instruction d'impression, car le caractère "é" ne fait pas partie de l'ASCII et je n'ai pas spécifié d'encodage. Je suppose que je ne comprends pas ce que signifie le codage par défaut ASCII.
ÉDITER
J'ai déplacé la modification dans la section Réponses et l' ai acceptée comme suggéré.
'\xe9'
dans un terminal configuré pour UTF-8 n'imprimera pasé
. Il imprimera un caractère de remplacement (généralement un point d'interrogation) car ce\xe9
n'est pas une séquence UTF-8 valide (il manque deux octets qui auraient dû suivre cet octet de début). Il ne sera certainement pas interprété comme Latin-1 à la place.\xe9
pour imprimeré
.Réponses:
Grâce à des bribes de diverses réponses, je pense que nous pouvons recoudre une explication.
En essayant d'imprimer une chaîne Unicode, u '\ xe9', Python essaie implicitement d'encoder cette chaîne en utilisant le schéma d'encodage actuellement stocké dans sys.stdout.encoding. Python récupère en fait ce paramètre à partir de l'environnement à partir duquel il a été lancé. S'il ne trouve pas de codage approprié dans l'environnement, ce n'est qu'alors qu'il revient à sa valeur par défaut , ASCII.
Par exemple, j'utilise un shell bash dont le codage par défaut est UTF-8. Si je démarre Python à partir de celui-ci, il récupère et utilise ce paramètre:
Quittons un instant le shell Python et définissons l'environnement de bash avec un faux encodage:
Ensuite, redémarrez le shell python et vérifiez qu'il revient bien à son encodage ascii par défaut.
Bingo!
Si vous essayez maintenant de sortir un caractère unicode en dehors de ascii, vous devriez obtenir un joli message d'erreur
Permet de quitter Python et de supprimer le shell bash.
Nous allons maintenant observer ce qui se passe après que Python a produit des chaînes. Pour cela, nous allons d'abord démarrer un shell bash dans un terminal graphique (j'utilise Gnome Terminal) et nous allons configurer le terminal pour décoder la sortie avec ISO-8859-1 aka latin-1 (les terminaux graphiques ont généralement une option pour Set Character Encodage dans l'un de leurs menus déroulants). Notez que cela ne change pas le codage de l'environnement shell réel , cela ne change que la façon dont le terminal lui-même décodera la sortie qui lui est donnée, un peu comme le fait un navigateur Web. Vous pouvez donc changer l'encodage du terminal, indépendamment de l'environnement du shell. Commençons ensuite Python à partir du shell et vérifions que sys.stdout.encoding est défini sur l'encodage de l'environnement du shell (UTF-8 pour moi):
(1) python renvoie la chaîne binaire telle quelle, le terminal la reçoit et essaie de faire correspondre sa valeur avec la table de caractères latin-1. En latin-1, 0xe9 ou 233 donne le caractère "é" et c'est donc ce que le terminal affiche.
(2) python tente de coder implicitement la chaîne Unicode avec le schéma actuellement défini dans sys.stdout.encoding, dans ce cas, c'est "UTF-8". Après le codage UTF-8, la chaîne binaire résultante est '\ xc3 \ xa9' (voir l'explication ultérieure). Le terminal reçoit le flux en tant que tel et essaie de décoder 0xc3a9 en utilisant latin-1, mais latin-1 passe de 0 à 255 et donc, ne décode que les flux 1 octet à la fois. 0xc3a9 fait 2 octets de long, le décodeur latin-1 l'interprète donc comme 0xc3 (195) et 0xa9 (169) et cela donne 2 caractères: Ã et ©.
(3) python encode le point de code unicode u '\ xe9' (233) avec le schéma latin-1. Il s'avère que la plage de points de code latin-1 est comprise entre 0 et 255 et pointe exactement le même caractère que Unicode dans cette plage. Par conséquent, les points de code Unicode dans cette plage donneront la même valeur lorsqu'ils sont encodés en latin-1. Ainsi, u '\ xe9' (233) encodé en latin-1 donnera également la chaîne binaire '\ xe9'. Le terminal reçoit cette valeur et essaie de la faire correspondre sur la carte de caractères latin-1. Tout comme le cas (1), il donne "é" et c'est ce qui est affiché.
Modifions maintenant les paramètres d'encodage du terminal en UTF-8 dans le menu déroulant (comme si vous changiez les paramètres d'encodage de votre navigateur Web). Pas besoin d'arrêter Python ou de redémarrer le shell. Le codage du terminal correspond maintenant à celui de Python. Essayons d'imprimer à nouveau:
(4) python génère un binaire chaîne telle quelle. Le terminal tente de décoder ce flux avec UTF-8. Mais UTF-8 ne comprend pas la valeur 0xe9 (voir l'explication ultérieure) et est donc incapable de la convertir en un point de code Unicode. Aucun point de code trouvé, aucun caractère imprimé.
(5) python tente d' encoder implicitement la chaîne Unicode avec tout ce qui se trouve dans sys.stdout.encoding. Toujours "UTF-8". La chaîne binaire résultante est '\ xc3 \ xa9'. Le terminal reçoit le flux et tente de décoder 0xc3a9 en utilisant également UTF-8. Il renvoie la valeur de code 0xe9 (233), qui sur la table de caractères Unicode pointe vers le symbole «é». Le terminal affiche "é".
(6) python encode une chaîne unicode avec latin-1, il donne une chaîne binaire avec la même valeur '\ xe9'. Encore une fois, pour le terminal, c'est à peu près la même chose que le cas (4).
Conclusions: - Python génère des chaînes non-Unicode sous forme de données brutes, sans tenir compte de son encodage par défaut. Le terminal les affiche juste si son encodage actuel correspond aux données. - Python génère des chaînes Unicode après les avoir encodées à l'aide du schéma spécifié dans sys.stdout.encoding. - Python obtient ce paramètre de l'environnement du shell. - le terminal affiche la sortie en fonction de ses propres paramètres d'encodage. - l'encodage du terminal est indépendant de celui du shell.
Plus de détails sur unicode, UTF-8 et latin-1:
Unicode est essentiellement une table de caractères dans laquelle certaines touches (points de code) ont été classiquement assignées pour pointer vers certains symboles. par exemple, par convention, il a été décidé que la clé 0xe9 (233) est la valeur pointant vers le symbole «é». ASCII et Unicode utilisent les mêmes points de code de 0 à 127, comme le font latin-1 et Unicode de 0 à 255. Autrement dit, 0x41 pointe vers «A» en ASCII, latin-1 et Unicode, 0xc8 pointe vers «Ü» dans latin-1 et Unicode, 0xe9 pointe vers «é» en latin-1 et Unicode.
Lorsque vous travaillez avec des appareils électroniques, les points de code Unicode ont besoin d'un moyen efficace d'être représentés électroniquement. C'est ce que sont les schémas d'encodage. Différents schémas de codage Unicode existent (utf7, UTF-8, UTF-16, UTF-32). L'approche de codage la plus intuitive et la plus simple serait d'utiliser simplement la valeur d'un point de code dans la carte Unicode comme valeur pour sa forme électronique, mais Unicode a actuellement plus d'un million de points de code, ce qui signifie que certains d'entre eux nécessitent 3 octets pour être exprimé. Pour travailler efficacement avec du texte, un mappage 1 à 1 serait plutôt peu pratique, car il exigerait que tous les points de code soient stockés exactement dans la même quantité d'espace, avec un minimum de 3 octets par caractère, quel que soit leur besoin réel.
La plupart des schémas d'encodage présentent des lacunes en termes d'espace, les plus économiques ne couvrent pas tous les points de code unicode, par exemple ascii ne couvre que les 128 premiers, tandis que latin-1 couvre les 256 premiers. D'autres qui essaient d'être plus complets finissent également par étant un gaspillage, car ils nécessitent plus d'octets que nécessaire, même pour les caractères «bon marché» courants. UTF-16 par exemple, utilise un minimum de 2 octets par caractère, y compris ceux de la plage ascii («B» qui vaut 65, nécessite toujours 2 octets de stockage en UTF-16). UTF-32 est encore plus coûteux car il stocke tous les caractères sur 4 octets.
UTF-8 a résolu intelligemment le dilemme, avec un schéma capable de stocker des points de code avec une quantité variable d'espaces d'octets. Dans le cadre de sa stratégie de codage, UTF-8 associe des points de code à des bits d'indicateur qui indiquent (vraisemblablement aux décodeurs) leurs besoins en espace et leurs limites.
Codage UTF-8 des points de code unicode dans la plage ascii (0-127):
Par exemple, le point de code Unicode pour 'B' est '0x42' ou 0100 0010 en binaire (comme nous l'avons dit, c'est la même chose en ASCII). Après encodage en UTF-8, il devient:
Codage UTF-8 des points de code Unicode au-dessus de 127 (non-ascii):
Par exemple, le point de code Unicode 'é' est 0xe9 (233).
Lorsque UTF-8 encode cette valeur, il détermine que la valeur est supérieure à 127 et inférieure à 2048 et doit donc être encodée sur 2 octets:
Le code Unicode 0xe9 pointe après le codage UTF-8 devient 0xc3a9. C'est exactement ainsi que le terminal le reçoit. Si votre terminal est configuré pour décoder des chaînes en utilisant latin-1 (l'un des encodages hérités non-unicode), vous verrez à ©, car il se trouve que 0xc3 en latin-1 pointe vers à et 0xa9 vers ©.
la source
Lorsque les caractères Unicode sont imprimés sur stdout,
sys.stdout.encoding
est utilisé. Un caractère non Unicode est supposé être danssys.stdout.encoding
et est simplement envoyé au terminal. Sur mon système (Python 2):sys.getdefaultencoding()
n'est utilisé que lorsque Python n'a pas d'autre option.Notez que Python 3.6 ou version ultérieure ignore les encodages sous Windows et utilise les API Unicode pour écrire Unicode sur le terminal. Aucun avertissement UnicodeEncodeError et le caractère correct s'affiche si la police le prend en charge. Même si la police ne la prend pas en charge, les caractères peuvent toujours être copiés-collés depuis le terminal vers une application avec une police de support et ce sera correct. Améliorer!
la source
Le Python REPL essaie de sélectionner le codage à utiliser dans votre environnement. S'il trouve quelque chose de sain, alors tout fonctionne. C'est quand il ne peut pas comprendre ce qui se passe que ça dérange.
la source
TypeError: readonly attribute
2.7.2Vous avez spécifié un encodage en entrant une chaîne Unicode explicite. Comparez les résultats de la non-utilisation du
u
préfixe.Dans le cas de,
\xe9
Python suppose votre encodage par défaut (Ascii), imprimant ainsi ... quelque chose de vide.la source
Ça marche pour moi:
la source
Selon les encodages et conversions de chaînes par défaut / implicites de Python :
print
estunicode
, c'estencode
d avec<file>.encoding
.encoding
n'est pas défini, leunicode
est implicitement converti enstr
(puisque le codec pour cela estsys.getdefaultencoding()
, c'estascii
-à- dire que tout caractère national entraînerait unUnicodeEncodeError
)encoding
est déduit de l'environnement. Il est généralement défini pour lestty
flux (à partir des paramètres régionaux du terminal), mais il est susceptible de ne pas être défini pour les tubesprint u'\xe9'
est susceptible de réussir lorsque la sortie est vers un terminal, et d'échouer s'il est redirigé. Une solution est deencode()
la chaîne avec le codage souhaité avantprint
ing.print
ingstr
, les octets sont envoyés au flux comme il est. Les glyphes affichés par le terminal dépendront de ses paramètres régionaux.la source