176 votes

Changer l'encodage par défaut de Python ?

J'ai beaucoup de problèmes "impossible de coder" et "impossible de décoder" avec Python lorsque je lance mes applications depuis la console. Mais dans le Eclipse PyDev IDE, le codage des caractères par défaut est fixé à UTF-8 et je vais bien.

J'ai fait des recherches sur le réglage de l'encodage par défaut, et les gens disent que Python supprime le fichier sys.setdefaultencoding au démarrage, et nous ne pouvons pas l'utiliser.

Quelle est donc la meilleure solution ?

1 votes

Voir l'article de blog L'Illusoire setdefaultencoding .

3 votes

The best solution is to learn to use encode and decode correctly instead of using hacks. Cela était certainement possible avec python2 au prix de ne jamais oublier de le faire / d'utiliser systématiquement votre propre interface. D'après mon expérience, cela devient très problématique lorsque vous écrivez du code que vous voulez faire fonctionner à la fois avec python2 et python3.

10voto

djc Points 6761

8voto

ibotty Points 669

Il existe 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.

Dans python 2, qui n'était pas aussi fortement typé en ce qui concerne l'encodage des chaînes de caractères, vous pouviez effectuer des opérations sur des chaînes de caractères encodées différemment, et réussir. Par exemple, l'opération suivante renverrait True .

u'Toshio' == 'Toshio'

Cela s'appliquerait à toute chaîne de caractères (normale, non fixée) encodée en sys.getdefaultencoding() qui a pris la valeur par défaut de ascii mais pas les autres.

L'encodage par défaut était censé être modifié à l'échelle du système en site.py mais pas ailleurs. Les bidouillages (également présentés ici) pour le définir dans les modules utilisateurs n'étaient que cela : des bidouillages, pas la solution.

Python 3 a modifié l'encodage du système pour qu'il prenne par défaut la valeur utf-8 (lorsque LC_CTYPE est sensible à l'unicode), mais le problème fondamental a été résolu par l'obligation d'encoder explicitement les chaînes "byte" lorsqu'elles sont utilisées avec des chaînes unicode.

5voto

kxr Points 31

D'abord : reload(sys) et la définition d'un encodage par défaut aléatoire pour le seul besoin d'un flux terminal de sortie est une mauvaise pratique. reload modifie souvent des choses dans sys qui ont été mises en place en fonction de l'environnement - par exemple, les flux sys.stdin/stdout, sys.excepthook, etc.

Résoudre le problème de l'encodage sur stdout

La meilleure solution que je connaisse pour résoudre le problème d'encodage de print dans les chaînes unicode et au-delà de l'ascii str (par exemple, à partir de littéraux) sur sys.stdout est de prendre soin d'un sys.stdout (objet de type fichier) qui est capable et éventuellement tolérant en ce qui concerne les besoins :

  • Lorsque sys.stdout.encoding est None pour une raison quelconque, ou inexistante, ou erronée ou "inférieure" à ce que le terminal ou le flux stdout est réellement capable de faire, alors essayez de fournir un .encoding attribut. Enfin, en remplaçant sys.stdout & sys.stderr par un objet de type fichier de traduction.

  • Lorsque le terminal / flux ne peut toujours pas encoder tous les caractères unicode qui apparaissent, et lorsque vous ne voulez pas casser print C'est justement à cause de cela que vous pouvez introduire un comportement d'encodage avec remplacement dans l'objet de type fichier de traduction.

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 __name__ == '__main__':
    if sys.stdout.isatty():
        sys.stdout = sys.stderr = SmartStdout()

    us = u'aouäöü'
    print us
    sys.stdout.flush()

Utilisation de chaînes de caractères simples au-delà de l'ascii dans le code Python 2 / 2 + 3

La seule bonne raison de changer l'encodage global par défaut (en UTF-8 uniquement) concerne, je pense, une application code source et non à cause de problèmes d'encodage de flux d'E/S : Pour écrire des chaînes de caractères au-delà de l'ascii dans le code sans être obligé de toujours utiliser u'string' unicode style escaping. Cela peut être fait de manière assez cohérente (malgré ce que disent les auteurs de anonbadger (voir l'article de l'auteur) en s'occupant d'une base de code source Python 2 ou Python 2 + 3 qui utilise de manière cohérente les chaînes de caractères ascii ou UTF-8 - dans la mesure où ces chaînes de caractères peuvent subir une conversion unicode silencieuse et se déplacer entre les modules ou aller vers stdout. Pour cela, préférez " # encoding: utf-8 " ou ascii (pas de déclaration). Modifier ou abandonner les bibliothèques qui dépendent encore de manière très stupide et fatale des erreurs d'encodage 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 de l'option 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 __name__ == '__main__':
    sys.stdout = sys.stderr = SmartStdout()
    set_defaultencoding_globally('utf-8') 
    s = 'aouäöü'
    print s

De cette façon, les chaînes de caractères et la plupart des opérations (à l'exception de l'itération des caractères) fonctionnent confortablement sans avoir à se soucier de la conversion unicode, comme s'il n'y avait que Python3. Les entrées/sorties de fichiers nécessitent bien sûr toujours une attention particulière en ce qui concerne les encodages - comme c'est le cas dans Python3.

Note : les chaînes plains sont ensuite implicitement converties de l'utf-8 à l'unicode en SmartStdout avant d'être converti en encodage du flux de sortie.

5voto

Att Righ Points 596

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

Cette approche fonctionne en remplaçant sys.stdout avec quelque chose qui n'est pas tout à fait un fichier (mais en utilisant uniquement les éléments de la bibliothèque standard). Cela peut poser des problèmes 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é par votre framework, cela peut être une approche raisonnable.

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

2voto

Dalton Bentley Points 147

Il s'agit d'un hack rapide pour tous ceux qui (1) sont sur une plate-forme Windows (2) utilisent Python 2.7 et (3) sont ennuyés parce qu'un joli logiciel (c'est-à-dire qui n'a pas été écrit par vous et qui n'est donc pas immédiatement candidat aux manœuvres d'impression de code/décode) n'affiche pas les "jolis caractères unicode" dans l'environnement IDLE (Pythonwin imprime bien l'unicode). Par exemple, les jolis symboles de logique du premier ordre que Stephan Boyer utilise dans la sortie de son proverbe pédagogique à l'adresse Vérificateur de logique du premier ordre .

Je n'aimais pas l'idée de forcer un rechargement du système et je n'arrivais pas à faire coopérer le système avec la mise en place de variables d'environnement comme PYTHONIOENCODING (j'ai essayé la variable d'environnement directe de Windows et aussi de la déposer dans un sitecustomize.py dans site-packages comme une ligne unique ='utf-8').

Donc, si vous êtes prêt à pirater votre chemin vers le succès, allez dans votre répertoire IDLE, typiquement : " C:\Python27\Lib\idlelib " Localisez le fichier IOBinding.py. Faites une copie de ce fichier et stockez-la ailleurs pour pouvoir revenir au comportement original quand vous le souhaitez. Ouvrez le fichier dans l'idlelib avec un éditeur (par exemple, IDLE). Allez dans 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 originale qui suit le ' essayez qui rendait la variable d'encodage égale à locale.getdefaultlocale (parce que cela vous donnera cp1252, ce que vous ne voulez pas) et, à la place, le transformer par force brute en 'utf-8' (en ajoutant la ligne ' encodage = 'utf-8 comme indiqué).

Je crois que cela n'affecte que l'affichage d'IDLE sur stdout et non l'encodage utilisé pour les noms de fichiers, etc. (qui est obtenu dans le filesystemencoding antérieur). Si vous avez un problème avec tout autre code que vous exécutez dans IDLE par la suite, remplacez simplement le fichier IOBinding.py par le fichier original non modifié.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X