Comment n'est-ce pas une copie exacte des dangers de sys.setdefaultencoding ('utf-8') ? Bien que cette (2010) demande soit antérieure à celle-là (2015)? Mais cette demande a aussi de bonnes réponses. Que faire? De plus, pour être clair, cette question n'a de sens que sur Python 2 et non sur 3, mais ce n'est nulle part étiqueté ou mentionné.
Selon la documentation: Cela vous permet de passer de l'ASCII par défaut à d'autres encodages tels que UTF-8, que le runtime Python utilisera chaque fois qu'il doit décoder un tampon de chaîne en unicode.
Cette fonction n'est disponible qu'au démarrage de Python, lorsque Python analyse l'environnement. Il doit être appelé dans un module à l'échelle du système,, Une sitecustomize.pyfois ce module évalué, la setdefaultencoding()fonction est supprimée du sysmodule.
La seule façon de l'utiliser est avec un hack de rechargement qui ramène l'attribut.
De plus, l'utilisation de sys.setdefaultencoding()a toujours été découragée , et elle est devenue un no-op dans py3k. L'encodage de py3k est câblé à "utf-8" et sa modification génère une erreur.
Je voudrais ajouter que l'encodage par défaut est également utilisé pour l' encodage (lors de l'écriture sys.stdoutlorsqu'il a un Noneencodage, comme lors de la redirection de la sortie d'un programme Python).
Eric O Lebigot
14
+1 pour "l'utilisation de sys.setdefaultencoding()a toujours été découragée"
jfs
7
«câblé à utf-8» n'est pas vrai, ce n'est pas câblé et ce n'est pas toujours le cas UTF-8. LC_ALL=en_US.UTF-8 python3 -c 'import sys; print(sys.stdout.encoding)'donne UTF-8mais LC_ALL=C python3 -c 'import sys; print(sys.stdout.encoding)'donneANSI_X3.4-1968 (ou peut-être autre chose)
Tino
7
@Tino, l'encodage de la console est distinct de l'encodage par défaut.
Alastair McCormack
59
tl; dr
La réponse est JAMAIS ! (sauf si vous savez vraiment ce que vous faites)
9/10 fois la solution peut être résolue avec une bonne compréhension de l'encodage / décodage.
1/10 des personnes ont une langue ou un environnement mal défini et doivent définir:
PYTHONIOENCODING="UTF-8"
dans leur environnement pour résoudre les problèmes d'impression de la console.
Qu'est ce que ça fait?
sys.setdefaultencoding("utf-8")(barré pour éviter la réutilisation) modifie l'encodage / décodage par défaut utilisé chaque fois que Python 2.x a besoin de convertir un Unicode () en str () (et vice-versa) et l'encodage n'est pas donné. C'est à dire:
str(u"\u20AC")
unicode("€")"{}".format(u"\u20AC")
Dans Python 2.x, l'encodage par défaut est défini sur ASCII et les exemples ci-dessus échoueront avec:
UnicodeDecodeError:'ascii' codec can't decode byte 0xe2 in position 0: ordinal not in range(128)
(Ma console est configurée en UTF-8, donc "€" = '\xe2\x82\xac' , exception sur \xe2)
ou
UnicodeEncodeError:'ascii' codec can't encode character u'\u20ac' in position 0: ordinal not in range(128)
sys.setdefaultencoding("utf-8")permettra à ceux-ci de travailler pour moi , mais ne fonctionnera pas nécessairement pour les personnes qui n'utilisent pas UTF-8. La valeur par défaut de ASCII garantit que les hypothèses de codage ne sont pas intégrées dans le code
Console
sys.setdefaultencoding("utf-8")a également pour effet secondaire de sembler corriger sys.stdout.encoding, utilisé lors de l'impression de caractères sur la console. Python utilise les paramètres régionaux de l'utilisateur (Linux / OS X / Un * x) ou la page de codes (Windows) pour définir cela. Parfois, les paramètres régionaux d'un utilisateur sont défectueux et nécessitent simplementPYTHONIOENCODING de corriger le codage de la console .
Exemple:
$ export LANG=en_GB.gibberish
$ python
>>> import sys
>>> sys.stdout.encoding
'ANSI_X3.4-1968'
>>> print u"\u20AC"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\u20ac' in position 0: ordinal not in range(128)
>>> exit()
$ PYTHONIOENCODING=UTF-8 python
>>> import sys
>>> sys.stdout.encoding
'UTF-8'
>>> print u"\u20AC"
€
Quel est le problème avec problème sys.setdefaultencoding ("utf-8") ?
Les gens développent contre Python 2.x depuis 16 ans, sachant que l'encodage par défaut est ASCII. UnicodeErrorDes méthodes de gestion des exceptions ont été écrites pour gérer les conversions chaîne en Unicode sur les chaînes qui contiennent des caractères non ASCII.
def welcome_message(byte_string):try:return u"%s runs your business"% byte_string
exceptUnicodeError:return u"%s runs your business"% unicode(byte_string,
encoding=detect_encoding(byte_string))print(welcome_message(u"Angstrom (Å®)".encode("latin-1"))
Avant de définir le codage par défaut, ce code ne pouvait pas décoder le «Å» dans le codage ascii et entrerait ensuite dans le gestionnaire d'exceptions pour deviner le codage et le transformer correctement en unicode. Impression: Angstrom (Å®) dirige votre entreprise. Une fois que vous avez défini le codage par défaut sur utf-8, le code trouvera que byte_string peut être interprété comme utf-8 et ainsi il modifiera les données et retournera ceci à la place: Angstrom (Ů) dirige votre entreprise.
Changer ce qui devrait être une constante aura des effets dramatiques sur les modules dont vous dépendez. Il est préférable de simplement corriger les données entrant et sortant de votre code.
Bien qu'il y ait des surprises sys.setdefaultencoding("utf-8"), il est bon de faire en sorte que le code se comporte davantage comme Python 3. Nous sommes en 2017 maintenant. Même lorsque vous avez écrit la réponse en 2015, je pense qu'il valait déjà mieux regarder en avant plutôt qu'en arrière. C'était en fait la solution la plus simple pour moi, quand j'ai trouvé que mon code se comportait différemment dans Python 2 selon que la sortie était redirigée (très mauvais problème pour Python 2). Inutile de dire que je l'ai déjà fait # coding: utf-8et que je n'ai pas besoin de solutions de contournement pour Python 3 (je dois en fait masquer la setdefaultencodingvérification de la version).
Yongwei Wu
C'est génial et cela fonctionne pour vous mais sys.setdefaultencoding("utf-8")ne rend pas votre code Py 2.x compatible avec Python 3. Il ne corrige pas non plus les modules externes qui supposent que l'encodage par défaut est ASCII. Rendre votre code compatible Python 3 est très simple et ne nécessite pas ce méchant hack. Par exemple, pourquoi cela pose des problèmes très réels, voir mon expérience avec Amazon qui joue avec cette hypothèse: stackoverflow.com/questions/39465220/…
Alastair McCormack
1
@AlastairMcCormack you rock, mon site existe depuis des mois et je ne savais pas quoi faire. Enfin, PYTHONIOENCODING="UTF-8"j'ai aidé mon environnement Python2.7 Django-1.11. Merci.
sam
Je sais que vous avez copié l'exemple, mais je peux trouver ce que contient le package detect_encoding.
dlamblin
@dlamblin L'exemple de code est pour prouver la citation et n'est pas censé être utilisé dans votre code. Imaginez que ce detect_encodingsoit une méthode qui pourrait détecter le codage d'une chaîne en fonction d'indices de langage.
Alastair McCormack
18
#!/usr/bin/env python#-*- coding: utf-8 -*-
u = u'moçambique'print u.encode("utf-8")print u
chmod +x test.py
./test.py
moçambique
moçambique
./test.py > output.txt
Traceback(most recent call last):File"./test.py", line 5,in<module>print u
UnicodeEncodeError:'ascii' codec can't encode character
u'\xe7' in position 2: ordinal not in range(128)
sur le shell fonctionne, l'envoi à sdtout non, donc c'est une solution de contournement, pour écrire sur stdout.
J'ai fait une autre approche, qui n'est pas exécutée si sys.stdout.encoding n'est pas défini, ou en d'autres termes, il faut d'abord exporter PYTHONIOENCODING = UTF-8 pour écrire dans stdout.
import sys
if(sys.stdout.encoding isNone):print>> sys.stderr,"please set python env PYTHONIOENCODING=UTF-8, example: export PYTHONIOENCODING=UTF-8, when write to stdout."
exit(1)
Cela ne répond pas à la question posée. Plutôt quelques réflexions tangentielles sur le sujet.
ivan_pozdeev
3
Le premier danger réside dans reload(sys).
Lorsque vous rechargez un module, vous obtenez en fait deux copies du module dans votre runtime. L'ancien module est un objet Python comme tout le reste, et reste en vie tant qu'il y a des références. Ainsi, la moitié des objets pointeront vers l'ancien module et l'autre moitié vers le nouveau. Lorsque vous apportez un changement, vous ne le verrez jamais venir lorsqu'un objet aléatoire ne voit pas le changement:
(ThisisIPython shell)In[1]:import sys
In[2]: sys.stdout
Out[2]:<colorama.ansitowin32.StreamWrapper at 0x3a2aac8>In[3]: reload(sys)<module 'sys'(built-in)>In[4]: sys.stdout
Out[4]:<open file '<stdout>', mode 'w' at 0x00000000022E20C0>In[11]:importIPython.terminal
In[14]:IPython.terminal.interactiveshell.sys.stdout
Out[14]:<colorama.ansitowin32.StreamWrapper at 0x3a9aac8>
Il peut y avoir du code qui repose sur le UnicodeErrorlancement pour une entrée non ASCII, ou qui effectue le transcodage avec un gestionnaire d'erreurs, ce qui produit maintenant un résultat inattendu. Et comme tout le code est testé avec le paramètre par défaut, vous êtes strictement sur le territoire "non pris en charge" ici , et personne ne vous donne de garanties sur le comportement de leur code.
Encore une fois, le pire est que vous ne le saurez jamais, car la conversion est implicite - vous ne savez pas vraiment quand et où cela se produit. (Python Zen, koan 2 ahoy!) Vous ne saurez jamais pourquoi (et si) votre code fonctionne sur un système et se brise sur un autre. (Ou mieux encore, fonctionne dans l'IDE et se brise dans la console.)
Réponses:
Selon la documentation: Cela vous permet de passer de l'ASCII par défaut à d'autres encodages tels que UTF-8, que le runtime Python utilisera chaque fois qu'il doit décoder un tampon de chaîne en unicode.
Cette fonction n'est disponible qu'au démarrage de Python, lorsque Python analyse l'environnement. Il doit être appelé dans un module à l'échelle du système,, Une
sitecustomize.py
fois ce module évalué, lasetdefaultencoding()
fonction est supprimée dusys
module.La seule façon de l'utiliser est avec un hack de rechargement qui ramène l'attribut.
De plus, l'utilisation de
sys.setdefaultencoding()
a toujours été découragée , et elle est devenue un no-op dans py3k. L'encodage de py3k est câblé à "utf-8" et sa modification génère une erreur.Je suggère quelques conseils pour lire:
la source
sys.stdout
lorsqu'il a unNone
encodage, comme lors de la redirection de la sortie d'un programme Python).sys.setdefaultencoding()
a toujours été découragée"UTF-8
.LC_ALL=en_US.UTF-8 python3 -c 'import sys; print(sys.stdout.encoding)'
donneUTF-8
maisLC_ALL=C python3 -c 'import sys; print(sys.stdout.encoding)'
donneANSI_X3.4-1968
(ou peut-être autre chose)tl; dr
La réponse est JAMAIS ! (sauf si vous savez vraiment ce que vous faites)
9/10 fois la solution peut être résolue avec une bonne compréhension de l'encodage / décodage.
1/10 des personnes ont une langue ou un environnement mal défini et doivent définir:
dans leur environnement pour résoudre les problèmes d'impression de la console.
Qu'est ce que ça fait?
(barré pour éviter la réutilisation) modifie l'encodage / décodage par défaut utilisé chaque fois que Python 2.x a besoin de convertir un Unicode () en str () (et vice-versa) et l'encodage n'est pas donné. C'est à dire:sys.setdefaultencoding("utf-8")
Dans Python 2.x, l'encodage par défaut est défini sur ASCII et les exemples ci-dessus échoueront avec:
(Ma console est configurée en UTF-8, donc
"€" = '\xe2\x82\xac'
, exception sur\xe2
)ou
permettra à ceux-ci de travailler pour moi , mais ne fonctionnera pas nécessairement pour les personnes qui n'utilisent pas UTF-8. La valeur par défaut de ASCII garantit que les hypothèses de codage ne sont pas intégrées dans le codesys.setdefaultencoding("utf-8")
Console
a également pour effet secondaire de sembler corrigersys.setdefaultencoding("utf-8")
sys.stdout.encoding
, utilisé lors de l'impression de caractères sur la console. Python utilise les paramètres régionaux de l'utilisateur (Linux / OS X / Un * x) ou la page de codes (Windows) pour définir cela. Parfois, les paramètres régionaux d'un utilisateur sont défectueux et nécessitent simplementPYTHONIOENCODING
de corriger le codage de la console .Exemple:
Quel est le problème avec
problème sys.setdefaultencoding ("utf-8")?Les gens développent contre Python 2.x depuis 16 ans, sachant que l'encodage par défaut est ASCII.
UnicodeError
Des méthodes de gestion des exceptions ont été écrites pour gérer les conversions chaîne en Unicode sur les chaînes qui contiennent des caractères non ASCII.De https://anonbadger.wordpress.com/2015/06/16/why-sys-setdefaultencoding-will-break-code/
Changer ce qui devrait être une constante aura des effets dramatiques sur les modules dont vous dépendez. Il est préférable de simplement corriger les données entrant et sortant de votre code.
Exemple de problème
Bien que le paramètre de codage par défaut en UTF-8 ne soit pas la cause principale dans l'exemple suivant, il montre comment les problèmes sont masqués et comment, lorsque le codage d'entrée change, le code se brise de manière non évidente: UnicodeDecodeError: le codec 'utf8' peut 't décoder l'octet 0x80 en position 3131: octet de départ invalide
la source
sys.setdefaultencoding("utf-8")
, il est bon de faire en sorte que le code se comporte davantage comme Python 3. Nous sommes en 2017 maintenant. Même lorsque vous avez écrit la réponse en 2015, je pense qu'il valait déjà mieux regarder en avant plutôt qu'en arrière. C'était en fait la solution la plus simple pour moi, quand j'ai trouvé que mon code se comportait différemment dans Python 2 selon que la sortie était redirigée (très mauvais problème pour Python 2). Inutile de dire que je l'ai déjà fait# coding: utf-8
et que je n'ai pas besoin de solutions de contournement pour Python 3 (je dois en fait masquer lasetdefaultencoding
vérification de la version).sys.setdefaultencoding("utf-8")
ne rend pas votre code Py 2.x compatible avec Python 3. Il ne corrige pas non plus les modules externes qui supposent que l'encodage par défaut est ASCII. Rendre votre code compatible Python 3 est très simple et ne nécessite pas ce méchant hack. Par exemple, pourquoi cela pose des problèmes très réels, voir mon expérience avec Amazon qui joue avec cette hypothèse: stackoverflow.com/questions/39465220/…PYTHONIOENCODING="UTF-8"
j'ai aidé mon environnement Python2.7 Django-1.11. Merci.detect_encoding
.detect_encoding
soit une méthode qui pourrait détecter le codage d'une chaîne en fonction d'indices de langage.sur le shell fonctionne, l'envoi à sdtout non, donc c'est une solution de contournement, pour écrire sur stdout.
J'ai fait une autre approche, qui n'est pas exécutée si sys.stdout.encoding n'est pas défini, ou en d'autres termes, il faut d'abord exporter PYTHONIOENCODING = UTF-8 pour écrire dans stdout.
donc, en utilisant le même exemple:
marchera
la source
Le premier danger réside dans
reload(sys)
.Lorsque vous rechargez un module, vous obtenez en fait deux copies du module dans votre runtime. L'ancien module est un objet Python comme tout le reste, et reste en vie tant qu'il y a des références. Ainsi, la moitié des objets pointeront vers l'ancien module et l'autre moitié vers le nouveau. Lorsque vous apportez un changement, vous ne le verrez jamais venir lorsqu'un objet aléatoire ne voit pas le changement:
Maintenant,
sys.setdefaultencoding()
bonTout ce que cela affecte, c'est la conversion implicite
str<->unicode
. Maintenant,utf-8
est le codage le plus sain sur la planète (rétrocompatible avec ASCII et tout), la conversion maintenant "fonctionne juste", qu'est - ce qui pourrait éventuellement mal tourner?Eh bien, n'importe quoi. Et c'est le danger.
UnicodeError
lancement pour une entrée non ASCII, ou qui effectue le transcodage avec un gestionnaire d'erreurs, ce qui produit maintenant un résultat inattendu. Et comme tout le code est testé avec le paramètre par défaut, vous êtes strictement sur le territoire "non pris en charge" ici , et personne ne vous donne de garanties sur le comportement de leur code.la source