Pourquoi ne pas utiliser sys.setdefaultencoding("utf-8") dans un script py?

j'ai vu peu de scripts py qui utilisent ceci en haut du script. Dans ce cas, il faut utiliser?

import sys
reload(sys)
sys.setdefaultencoding("utf-8")
137
demandé sur smci 2010-09-30 11:46:08

4 réponses

selon la documentation: cela vous permet de passer de L'ASCII par défaut à D'autres encodages tels que UTF-8, que L'exécution Python utilisera chaque fois qu'il devra décoder un tampon de chaîne vers unicode.

cette fonction n'est disponible qu'au démarrage de Python, lorsque Python scanne l'environnement. Il doit être appelé dans un module à l'échelle du système, sitecustomize.py , après que ce module a été évalué, la fonction setdefaultencoding() est retirée du module sys .

La seule façon de l'utiliser est avec un rechargement hack qui apporte de l'attribut.

aussi, l'utilisation de sys.setdefaultencoding() a toujours été découragée , et il est devenu un no-op dans py3k. L'encodage de py3k est câblé à "utf-8" et sa modification soulève une erreur.

je suggère quelques conseils pour la lecture:

125
répondu pyfunc 2016-05-13 21:59:12

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 les gens ont un endroit ou un environnement mal défini et ont besoin de définir:

PYTHONIOENCODING="UTF-8"  

dans leur environnement pour résoudre les problèmes d'impression sur console.

Que fait-il?

sys.setdefaultencoding("utf-8") (barred through to avoid re-use) change l'encodage/décodage par défaut utilisé chaque fois que Python 2.x doit convertir un Unicode () en str () (et vice-versa) et l'encodage n'est pas donné. I. e:

str(u"\u20AC")
unicode("€")
"{}".format(u"\u20AC") 

En Python 2.x, le codage par défaut est défini à 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é comme UTF-8, donc "€" = '\xe2\x82\xac' , donc 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 à ces derniers de travailler pour me , 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 d'encodage ne sont pas transformées en code

Console

sys.setdefaultencoding("utf-8") a aussi pour effet secondaire d'apparaître pour fixer sys.stdout.encoding , utilisé lors de l'impression des caractères à la console. Python utilise la locale de l'utilisateur (Linux/OS X/Un*x) ou le codepage (Windows) pour définir ceci. De temps en temps, la locale d'un utilisateur est cassée et il suffit de PYTHONIOENCODING pour corriger le encodage 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"
€

Ce qui est si mal avec sys.setdefaultencoding ("utf-8") ?

les gens se sont développés contre Python 2.x de 16 ans sur la compréhension que l'encodage par défaut est ASCII. UnicodeError les méthodes de gestion des exceptions ont été écrites pour gérer les conversions string to Unicode sur les chaînes qui contiennent des non-ASCII.

de https://anonbadger.wordpress.com/2015/06/16/why-sys-setdefaultencoding-will-break-code /

def welcome_message(byte_string):
    try:
        return u"%s runs your business" % byte_string
    except UnicodeError:
        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 defaultencoding ce code ne pourrait pas décoder le " Å " dans l'encodage ascii et ensuite entrer le gestionnaire d'exception pour deviner l'encodage et le transformer correctement en unicode. Impression: Angstrom (Å®) gère votre entreprise. Une fois que vous avez défini le defaultencoding à utf-8, le code va trouver que le byte_string peut être interprété comme utf-8 et il va donc modifier les données et retourner ceci à la place: Angstrom (¿) exécute votre affaires.

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

alors que le paramétrage de defaultencoding à UTF-8 n'est pas la cause fondamentale dans l'exemple suivant, il montre comment les problèmes sont masqués et comment, lorsque l'encodage d'entrée change, le code se brise en une manière peu évidente: UnicodeDecodeError: 'utf8' codec ne peut pas décoder les octets 0x80 en position 3131: invalid octet de départ

43
répondu Alastair McCormack 2017-08-03 12:52:34
#!/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 les travaux shell, l'envoi à sdtout Non , donc c'est un contournement, pour écrire à stdout .

j'ai fait une autre approche, qui n'est pas exécutée si sys.la sortie standard stdout.l'encodage n'est pas défini, ou en d'autres mots , il faut exporter PYTHONIOENCODING=UTF-8 en premier pour écrire à stdout.

import sys
if (sys.stdout.encoding is None):            
    print >> sys.stderr, "please set python env PYTHONIOENCODING=UTF-8, example: export PYTHONIOENCODING=UTF-8, when write to stdout." 
    exit(1)



donc, en utilisant le même exemple:

export PYTHONIOENCODING=UTF-8
./test.py > output.txt

fonctionnera

17
répondu Sérgio 2011-07-19 03:50:16
  • le premier danger réside dans reload(sys) .

    Lorsque vous rechargez un module, vous obtenez en fait deux copies du module dans votre exécution. Le vieux module est un objet Python comme tout le reste, et reste vivant tant qu'il y a des références à lui. Ainsi, la moitié des objets sera pointant vers l'ancien module, et la moitié de la nouvelle. quand vous faites quelques changements, vous ne le verrez jamais venir quand un objet aléatoire ne voit pas le changement:

    (This is IPython 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]: import IPython.terminal
    
    In [14]: IPython.terminal.interactiveshell.sys.stdout
    Out[14]: <colorama.ansitowin32.StreamWrapper at 0x3a9aac8>
    
  • Maintenant, sys.setdefaultencoding() bon

    Tout ce qu'il affecte est la conversion implicite str<->unicode . Maintenant, utf-8 est le codage le plus sain sur la planète (rétro-compatible avec ASCII et tout), la conversion maintenant "fonctionne juste", qu'est-ce qui pourrait aller mal?

    enfin, n'importe quoi. Et c'est le danger.

    • il peut y avoir un code qui s'appuie sur le UnicodeError lancé pour l'entrée non-ASCII, ou fait le transcodage avec un gestionnaire d'erreurs, qui produit maintenant un résultat inattendu. Et puisque tout le code est testé avec le réglage par défaut, vous êtes strictement sur" unsupported "territoire ici , et personne ne vous donne des garanties sur la façon dont leur code se comportera.
    • le transcodage peut produire des résultats inattendus ou inutilisables si tout le système n'utilise pas UTF-8 parce que Python 2 a en fait plusieurs" encodages par défaut de chaîne de caractères " . (Rappelez-vous, un programme doit travailler pour le client, sur l'équipement du client.)
      • encore une fois, la pire chose est vous ne saurez jamais que parce que la conversion est implicite -- vous ne savez pas vraiment quand et là où ça se passe. (Python Zen, koan 2 ahoy!) Vous ne saurez jamais pourquoi (et si) votre code fonctionne sur un système et les pauses sur l'autre. (Ou encore mieux, travaille en IDE et casse en console.)
3
répondu ivan_pozdeev 2018-04-22 19:24:16