web-dev-qa-db-fra.com

Changer l'encodage par défaut de Python?

J'ai de nombreux problèmes "impossible à encoder" et "impossible à décoder" avec Python lorsque j'exécute mes applications à partir de la console. Mais dans le EclipsePyDev IDE, le codage de caractères par défaut est défini sur UTF-8 , et tout va bien.

J'ai cherché autour de définir le codage par défaut, et les gens disent que Python supprime la fonction sys.setdefaultencoding au démarrage, et nous ne pouvons pas l'utiliser.

Alors, quelle est la meilleure solution pour cela?

117
Ali Nadalizadeh

Voici une méthode plus simple (hack) qui vous rend la fonction setdefaultencoding() qui a été supprimée de sys:

import sys
# sys.setdefaultencoding() does not exist, here!
reload(sys)  # Reload does the trick!
sys.setdefaultencoding('UTF8')

Ce n’est pas une chose sûre à faire, cependant: c’est évidemment un hack, puisque sys.setdefaultencoding() est volontairement supprimé de sys au démarrage de Python. La réactiver et changer le codage par défaut peut interrompre le code reposant sur ASCII étant la valeur par défaut (ce code peut être tiers, ce qui rendrait généralement la correction impossible ou dangereuse).

134
Eric O Lebigot

A) Pour contrôler la sortie de sys.getdefaultencoding():

python -c 'import sys; print(sys.getdefaultencoding())'

ascii

Ensuite

echo "import sys; sys.setdefaultencoding('utf-16-be')" > sitecustomize.py

et 

PYTHONPATH=".:$PYTHONPATH" python -c 'import sys; print(sys.getdefaultencoding())'

utf-16-be

Vous pouvez placer votre sitecustomize.py plus haut dans votre PYTHONPATH.

Aussi, vous voudrez peut-être essayer reload(sys).setdefaultencoding by @EOL 

B) Pour contrôler stdin.encoding et stdout.encoding vous voulez définir PYTHONIOENCODING:

python -c 'import sys; print(sys.stdin.encoding, sys.stdout.encoding)'

ascii ascii

Ensuite 

PYTHONIOENCODING="utf-16-be" python -c 'import sys; 
print(sys.stdin.encoding, sys.stdout.encoding)'

utf-16-be utf-16-be

Enfin: vous pouvez utiliser A) ou B) ou les deux!

46
lukmdo

Depuis PyDev 3.4.1, le codage par défaut n’est plus modifié. Voir ce ticket pour plus de détails.

Pour les versions antérieures, une solution consiste à s'assurer que PyDev ne s'exécute pas avec UTF-8 comme codage par défaut. Sous Eclipse, exécutez les paramètres de la boîte de dialogue ("exécuter les configurations", si mes souvenirs sont exacts); vous pouvez choisir le codage par défaut sur l'onglet commun. Changez-le en US-ASCII si vous voulez que ces erreurs se produisent «tôt» (autrement dit: dans votre environnement PyDev). Voir également un article de blog original pour cette solution de contournement .

17
ChristopheD

En ce qui concerne python2 (et python2 uniquement), certaines des réponses précédentes reposent sur l'utilisation du hack suivant:

import sys
reload(sys)  # Reload is a hack
sys.setdefaultencoding('UTF8')

Il est déconseillé de l'utiliser (cochez ceci ou ceci )

Dans mon cas, cela a un effet secondaire: j'utilise des ordinateurs portables ipython, et une fois que je lance le code, la fonction "imprimer" ne fonctionne plus. J'imagine qu'il y aurait une solution, mais je pense toujours que le piratage ne devrait pas être la bonne option.

Après avoir essayé de nombreuses options, celle qui a fonctionné pour moi a été en utilisant le même code dans le sitecustomize.py, où cet élément de code est censé être. Après évaluation de ce module, la fonction setdefaultencoding est supprimée de sys.

La solution consiste donc à ajouter au fichier /usr/lib/python2.7/sitecustomize.py le code:

import sys
sys.setdefaultencoding('UTF8')

Lorsque j'utilise virtualenvwrapper, le fichier que je modifie est ~/.virtualenvs/venv-name/lib/python2.7/sitecustomize.py.

Et quand j’utilise avec les cahiers et conda en python, c’est ~/anaconda2/lib/python2.7/sitecustomize.py

12
kiril

Il y a un article de blog perspicace à ce sujet.

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

Je paraphrase son contenu ci-dessous.

En python 2, qui n’était pas aussi fortement typé en ce qui concerne le codage des chaînes, vous pouvez effectuer des opérations sur des chaînes codées différemment et réussir. Par exemple. ce qui suit retournerait True.

u'Toshio' == 'Toshio'

Cela serait valable pour toutes les chaînes (normales, non préfixées) codées dans sys.getdefaultencoding(), dont la valeur par défaut est ascii, mais pas les autres.

Le codage par défaut devait être modifié à l'échelle du système dans site.py, mais pas ailleurs. Les hacks (également présentés ici) pour le définir dans les modules utilisateur ne sont que ça: des hacks, pas la solution.

Python 3 a modifié l'encodage système par défaut en utf-8 (lorsque LC_CTYPE est compatible avec Unicode), mais le problème fondamental a été résolu avec l'obligation d'encoder explicitement les chaînes "octets" chaque fois qu'elles sont utilisées avec des chaînes Unicode.

7
ibotty

Premièrement: reload(sys) et la définition d’un encodage aléatoire par défaut concernant uniquement le besoin d’un flux de terminal de sortie est une mauvaise pratique. reload modifie souvent les éléments du système qui ont été mis en place en fonction de l'environnement - par exemple. sys.stdin/flux stdout, sys.excepthook, etc. 

Résoudre le problème d'encodage sur stdout

La meilleure solution que je connaisse pour résoudre le problème de codage de print 'ing chaînes Unicode et de Beyond-ascii str (par exemple à partir de littéraux) sur sys.stdout est: éventuellement tolérante vis-à-vis des besoins:

  • Lorsque sys.stdout.encoding est None pour une raison quelconque, ou inexistant, ou si, à tort, faux ou "moins" que ce dont le terminal ou le flux stdout est réellement capable, essayez alors de fournir un attribut correct .encoding. Enfin, remplacez sys.stdout & sys.stderr par un objet de type fichier en cours de traduction.

  • Lorsque le terminal/flux ne peut toujours pas encoder tous les caractères Unicode qui se produisent, et lorsque vous ne voulez pas interrompre les print simplement à cause de cela, vous pouvez introduire un comportement encodage avec remplacement dans l'objet de type fichier.

Voici un exemple:

#!/usr/bin/env python
# encoding: utf-8
import sys

class SmartStdout:
    def __init__(self, encoding=None, org_stdout=None):
        if org_stdout is None:
            org_stdout = getattr(sys.stdout, 'org_stdout', sys.stdout)
        self.org_stdout = org_stdout
        self.encoding = encoding or \
                        getattr(org_stdout, 'encoding', None) or 'utf-8'
    def write(self, s):
        self.org_stdout.write(s.encode(self.encoding, 'backslashreplace'))
    def __getattr__(self, name):
        return getattr(self.org_stdout, name)

if __== '__main__':
    if sys.stdout.isatty():
        sys.stdout = sys.stderr = SmartStdout()

    us = u'aouäöüфżß²'
    print us
    sys.stdout.flush()

Utilisation de littéraux au-delà des chaînes ascii dans le code Python 2/2 + 3

La seule bonne raison de modifier le codage global par défaut (uniquement en UTF-8) est liée à une application code source decision - et non à des problèmes de codage de flux d'E/S: pour l'écriture de littéraux de chaîne Beyond-Ascii dans code sans être obligé de toujours utiliser le style u'string' d'échappement Unicode. Cela peut être fait de manière assez cohérente (malgré ce que dit l'article de anonbadger) en prenant soin de la base de code source Python 2 ou Python 2 + 3 qui utilise les littéraux de chaîne standard ascii ou UTF-8 de manière cohérente - dans la mesure du possible. les chaînes subissent potentiellement une conversion unicode silencieuse et se déplacent entre les modules ou peuvent aller sur stdout. Pour cela, préférez "# encoding: utf-8" ou ascii (pas de déclaration). Modifie ou supprime des bibliothèques qui reposent toujours de manière très stupide sur les erreurs de codage par défaut ascii au-delà de chr # 127 (ce qui est rare aujourd'hui).

Et faites comme ceci au démarrage de l'application (et/ou via sitecustomize.py) en plus du schéma SmartStdout ci-dessus - sans utiliser reload(sys):

...
def set_defaultencoding_globally(encoding='utf-8'):
    assert sys.getdefaultencoding() in ('ascii', 'mbcs', encoding)
    import imp
    _sys_org = imp.load_dynamic('_sys_org', 'sys')
    _sys_org.setdefaultencoding(encoding)

if __== '__main__':
    sys.stdout = sys.stderr = SmartStdout()
    set_defaultencoding_globally('utf-8') 
    s = 'aouäöüфżß²'
    print s

De cette manière, les littéraux de chaîne et la plupart des opérations (à l'exception de l'itération de caractère) fonctionnent sans penser à la conversion unicode comme s'il n'y aurait que Python3. Les entrées/sorties de fichiers nécessitent bien sûr toujours une attention particulière en ce qui concerne les codages - comme dans Python3.

Remarque: les chaînes de plaines sont ensuite implicitement converties d'utf-8 en unicode dans SmartStdout avant d'être converties dans le flux de sortie contenant.

2
kxr

Cela a résolu le problème pour moi.

import os
os.environ["PYTHONIOENCODING"] = "utf-8"
2
twasbrillig

Ceci est un hack rapide pour quiconque (1) sur une plate-forme Windows (2) exécutant Python 2.7 et (3) agacé par le fait qu’un joli logiciel (c’est-à-dire qu’il n’a pas été écrit par vous et ne soit donc pas immédiatement candidat à l’impression encodage/décodage manœuvres) n’affichera pas les "jolis caractères unicode" dans l’environnement IDLE (Pythonwin imprime unicode fin), Par exemple, les symboles de logique de premier ordre ordonnés que Stephan Boyer utilise dans la sortie de son démonstrateur pédagogique à Démonstrateur de logique de premier ordre .

Je n’aimais pas l’idée de forcer une recharge système et je ne pouvais pas amener le système à coopérer avec la définition de variables d’environnement telles que PYTHONIOENCODING (variable d’environnement Windows directe, mais aussi la suppression dans un sitecustomize.py dans des packages de site doublure = 'utf-8').

Donc, si vous êtes prêt à pirater votre chemin vers le succès, allez dans votre répertoire IDLE, généralement: "C:\Python27\Lib\idlelib" Localisez le fichier IOBinding.py. Faites une copie de ce fichier et stockez-le ailleurs afin de pouvoir revenir au comportement d'origine lorsque vous le souhaitez. Ouvrez le fichier dans idlelib avec un éditeur (par exemple, IDLE). Aller à cette zone de code:

# Encoding for file names
filesystemencoding = sys.getfilesystemencoding()

encoding = "ascii"
if sys.platform == 'win32':
    # On Windows, we could use "mbcs". However, to give the user
    # a portable encoding name, we need to find the code page 
    try:
        # --> 6/5/17 hack to force IDLE to display utf-8 rather than cp1252
        # --> encoding = locale.getdefaultlocale()[1]
        encoding = 'utf-8'
        codecs.lookup(encoding)
    except LookupError:
        pass

En d'autres termes, commentez la ligne de code d'origine à la suite de 'try' qui rendait la variable d'encodage égale à locale.getdefaultlocale (car cela vous donnera cp1252 dont vous ne voulez pas) et plutôt force brutalement à 'utf-8' (en ajoutant la ligne 'encoding =' utf-8 'comme indiqué). 

Je crois que cela affecte uniquement l'affichage IDLE sur stdout et pas l'encodage utilisé pour les noms de fichier, etc. (obtenu dans le système de fichiers précédent). Si vous rencontrez un problème avec un autre code que vous exécutez ultérieurement dans IDLE, remplacez simplement le fichier IOBinding.py par le fichier d'origine non modifié.

0
Dalton Bentley

Voici l’approche que j’avais utilisée pour produire du code compatible avec python2 et python3 et produisant toujours la sortie utf8. J'ai trouvé cette réponse ailleurs, mais je ne me souviens plus de la source.

Cette approche fonctionne en remplaçant sys.stdout par quelque chose qui n'est pas tout à fait comme un fichier (mais n'utilise toujours que des éléments de la bibliothèque standard). Cela peut poser problème pour vos bibliothèques sous-jacentes, mais dans le cas simple où vous avez un bon contrôle sur la façon dont sys.stdout out est utilisé dans votre infrastructure, cela peut constituer une approche raisonnable.

sys.stdout = io.open(sys.stdout.fileno(), 'w', encoding='utf8')
0
Att Righ