web-dev-qa-db-fra.com

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

J'ai vu peu de scripts py qui l'utilisent en haut du script. Dans quels cas faut-il l'utiliser?

import sys
reload(sys)
sys.setdefaultencoding("utf-8")
155
mlzboy

Selon la documentation: Ceci vous permet de passer du 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 pour Unicode.

Cette fonction est uniquement disponible à Python heure de démarrage, lorsque Python analyse l'environnement. Elle doit être appelée dans un module système, sitecustomize.py. Une fois ce module évalué, la fonction setdefaultencoding() est supprimée du module sys.

La seule façon de l'utiliser réellement est d'utiliser un hack de rechargement qui ramène l'attribut.

De plus, l'utilisation de sys.setdefaultencoding() a toujours été découragée , et c'est devenu un no-op dans py3k. Le codage de py3k est câblé en dur sur "utf-8" et sa modification soulève une erreur.

Je suggère quelques indications pour la lecture:

135
pyfunc

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 compréhension correcte du codage/décodage.

1/10 personnes ont des paramètres régionaux ou un environnement incorrectement définis 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) change le codage/décodage par défaut utilisé chaque fois que Python 2.x doit convertir un Unicode () en str () (et vice-versa) et que le codage n'est pas donné. C'est à dire:

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

Dans Python 2.x, le codage 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', donc une 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 fonctionner 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 intégrées au code

Console

sys.setdefaultencoding("utf-8") semble également avoir pour effet de 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 le définir. De temps en temps, les paramètres régionaux d'un utilisateur sont rompus et ne nécessitent que PYTHONIOENCODING pour 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 sys.setdefaultencoding ("utf-8")?

Cela fait 16 ans que les gens se développent contre Python 2.x, sachant que le codage par défaut est ASCII. UnicodeError des méthodes de traitement des exceptions ont été écrites pour gérer les conversions de chaîne en Unicode sur des chaînes contenant des éléments 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 le codage par défaut, ce code ne pourrait pas décoder le "Å" dans le codage ascii, puis entrerait dans le gestionnaire d’exceptions pour deviner le codage et le convertir 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 détecte que la chaîne byte_string peut être interprétée en tant que utf-8. Il modifie donc les données et renvoie le résultat suivant: Angstrom (Ů) gère 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 qui entrent et sortent de votre code.

Exemple de problème

Bien que la définition du codage par défaut sur UTF-8 ne soit pas la cause première de l'exemple suivant, elle montre comment les problèmes sont masqués et comment, lorsque le codage en entrée est modifié, le code se rompt de manière non évidente: nicodeDecodeError: ' Le codec utf8 ne peut pas décoder l'octet 0x80 en position 3131: octet de début non valide

54
Alastair McCormack
#!/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 Shell fonctionne, en envoyant à sdtout pas, donc c’est une solution de contournement, d’é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, nécessite une exportation PYTHONIOENCODING = UTF-8 en premier pour écrire sur 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

marchera

19
Sérgio
  • Le premier danger réside dans reload(sys).

    Lorsque vous rechargez un module, vous obtenez deux copies du module dans votre environnement d'exécution. 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 pointera vers l'ancien module et l'autre moitié vers le nouveau. Lorsque vous apportez des modifications, vous ne les 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() convenable

    La conversion implicite n’est affectée que par str<->unicode . Maintenant, utf-8 est l’encodage le plus sain de la planète (compatible avec la version antérieure de ASCII et tous), la conversion fonctionne désormais "simplement", ce qui pourrait éventuellement va mal?

    Eh bien, n'importe quoi. Et c'est le danger.

    • Il peut y avoir un code qui repose sur le UnicodeError levé pour une entrée non-ASCII, ou effectue le transcodage avec un gestionnaire d'erreurs, qui produit maintenant un résultat inattendu. Et puisque tout le code est testé avec le paramètre par défaut, vous êtes strictement sur un territoire "non pris en charge", , et personne ne vous garantit le code va se comporter.
    • Le transcodage peut produire des résultats inattendus ou inutilisables si toutes les unités du système n’utilisent pas UTF-8 car Python 2 a en réalité plusieurs "encodages de chaîne par défaut" indépendants] . (N'oubliez pas qu'un programme doit fonctionner pour le client, sur son équipement.)
      • Encore une fois, le pire est vous ne saurez jamais que 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 casse sur un autre. (Ou mieux encore, fonctionne dans IDE et s'interrompt dans la console.)
3
ivan_pozdeev