Question

Lors du transfert de la sortie d'un programme Python, l'interpréteur Python ne comprend pas l'encodage et le définit sur Aucun. Cela signifie un programme comme celui-ci:

# -*- coding: utf-8 -*-
print u"åäö"

fonctionnera correctement s'il est exécuté normalement, mais échoue avec:

  

UnicodeEncodeError: le codec 'ascii' ne peut pas coder le caractère u '\ xa0' en position 0: l'ordinal n'est pas dans la plage (128)

lorsqu’il est utilisé dans une séquence de tubes.

Quel est le meilleur moyen de faire en sorte que cela fonctionne lors de la tuyauterie? Puis-je simplement lui dire d'utiliser tout ce qui est codé par le shell / système de fichiers / ce qu'il utilise?

Les suggestions que j'ai vues jusqu'ici consistent à modifier directement votre site.py ou à coder en dur le codage par défaut à l'aide de ce hack:

# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
print u"åäö"

Existe-t-il un meilleur moyen de faire fonctionner la tuyauterie?

Était-ce utile?

La solution

Votre code fonctionne lorsqu'il est exécuté dans un script car Python code la sortie selon le code utilisé par votre application de terminal. Si vous faites du piping, vous devez l’encoder vous-même.

En règle générale, utilisez toujours Unicode en interne. Décodez ce que vous recevez et encodez ce que vous envoyez.

# -*- coding: utf-8 -*-
print u"åäö".encode('utf-8')

Un autre exemple didactique est un programme Python permettant de convertir entre ISO-8859-1 et UTF-8, en mettant tout en majuscule entre les deux.

import sys
for line in sys.stdin:
    # Decode what you receive:
    line = line.decode('iso8859-1')

    # Work with Unicode internally:
    line = line.upper()

    # Encode what you send:
    line = line.encode('utf-8')
    sys.stdout.write(line)

La définition du codage système par défaut est une mauvaise idée, car certains modules et bibliothèques que vous utilisez peuvent s’appuyer sur le fait qu’il s’agit d’un code ASCII. Ne le fais pas.

Autres conseils

Tout d'abord, en ce qui concerne cette solution:

# -*- coding: utf-8 -*-
print u"åäö".encode('utf-8')

Il n’est pas pratique d’imprimer explicitement avec un encodage donné à chaque fois. Ce serait répétitif et sujet aux erreurs.

Une meilleure solution consiste à changer sys.stdout au début de votre programme, pour coder avec le codage sélectionné. Voici une solution que j'ai trouvée sur Python: Comment est sys .stdout.encoding choisi? , en particulier un commentaire de & "; toka &";:

import sys
import codecs
sys.stdout = codecs.getwriter('utf8')(sys.stdout)

Vous pouvez essayer de changer la variable d'environnement " PYTHONIOENCODING " à & "; utf_8 &"; J'ai écrit une page sur mon épreuve avec ce problème .

Tl; dr de l'article de blog:

vous donne

utf_8
False
ANSI_X3.4-1968
ascii
utf_8
ö ☺ ☻
export PYTHONIOENCODING=utf-8

faire le travail, mais ne peut pas le définir sur python lui-même ...

Ce que nous pouvons faire est de vérifier si le paramètre n'est pas défini et d'indiquer à l'utilisateur de le définir avant le script d'appel avec:

if __name__ == '__main__':
    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)

Mise à jour pour répondre au commentaire: le problème n’existe que lorsqu’on passe à la sortie standard. J'ai testé dans Fedora 25 Python 2.7.13

python --version
Python 2.7.13

chat b.py

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

print sys.stdout.encoding

en cours d'exécution ./b.py

UTF-8

en cours d'exécution ./b.py | moins

None

J'ai eu un problème similaire la semaine dernière . C'était facile à corriger dans mon IDE (PyCharm).

Voici ma solution:

À partir de la barre de menus de PyCharm: File - > Paramètres ... - & Gt; Éditeur - & Gt; Fichier Encodages, puis définissez: & "; IDE Encoding &"; & "Project Encoding &"; et " Encodage par défaut pour les fichiers de propriétés " Tout à UTF-8 et elle fonctionne maintenant comme un charme.

J'espère que ça aide!

Une version assainie et discutable de la réponse de Craig McQueen.

import sys, codecs
class EncodedOut:
    def __init__(self, enc):
        self.enc = enc
        self.stdout = sys.stdout
    def __enter__(self):
        if sys.stdout.encoding is None:
            w = codecs.getwriter(self.enc)
            sys.stdout = w(sys.stdout)
    def __exit__(self, exc_ty, exc_val, tb):
        sys.stdout = self.stdout

Utilisation:

with EncodedOut('utf-8'):
    print u'ÅÄÖåäö'

Je pourrais " automatiser " avec un appel à:

def __fix_io_encoding(last_resort_default='UTF-8'):
  import sys
  if [x for x in (sys.stdin,sys.stdout,sys.stderr) if x.encoding is None] :
      import os
      defEnc = None
      if defEnc is None :
        try:
          import locale
          defEnc = locale.getpreferredencoding()
        except: pass
      if defEnc is None :
        try: defEnc = sys.getfilesystemencoding()
        except: pass
      if defEnc is None :
        try: defEnc = sys.stdin.encoding
        except: pass
      if defEnc is None :
        defEnc = last_resort_default
      os.environ['PYTHONIOENCODING'] = os.environ.get("PYTHONIOENCODING",defEnc)
      os.execvpe(sys.argv[0],sys.argv,os.environ)
__fix_io_encoding() ; del __fix_io_encoding

Oui, il est possible d’obtenir une boucle infinie ici si & "; setenv &"; échoue.

Je pensais juste mentionner quelque chose ici que je devais passer beaucoup de temps à expérimenter avant de finalement comprendre ce qui se passait. Cela peut sembler si évident à tout le monde ici qu’ils n’ont pas pris la peine de le mentionner. Mais cela m’aurait aidé s’ils l’avaient fait, donc sur ce principe ...!

NB: J'utilise spécifiquement Jython , version 2.7, ce qui pourrait ne pas être valable. CPython ...

NB2: les deux premières lignes de mon fichier .py sont les suivantes:

# -*- coding: utf-8 -*-
from __future__ import print_function

Le ".% " (AKA & "; Opérateur d'interpolation &"); Le mécanisme de construction de la chaîne pose également des problèmes supplémentaires ... Si le codage par défaut de l'environnement & "; L'environnement &"; est ASCII et que vous essayez de faire quelque chose comme

print( "bonjour, %s" % "fréd" )  # Call this "print A"

Vous n'aurez aucune difficulté à exécuter Eclipse ... Dans une CLI Windows (fenêtre DOS), vous constaterez que le codage est page de code 850 (mon Windows & nbsp; 7 systèmes d'exploitation) ou quelque chose de similaire, capable de gérer les caractères accentués au moins européens, cela fonctionnera donc.

print( u"bonjour, %s" % "fréd" ) # Call this "print B"

fonctionnera également.

Si, OTOH, vous dirigez vers un fichier à partir de la CLI, le codage stdout sera None, qui passera par défaut en ASCII (sur mon système d’exploitation de toute façon), qui ne pourra traiter aucune des impressions précédentes ... (erreur de codage redoutée).

Vous pouvez alors penser à rediriger votre sortie standard en utilisant

sys.stdout = codecs.getwriter('utf8')(sys.stdout)

et essayez de lancer la tuyauterie CLI vers un fichier ... Très curieusement, l’impression A ci-dessus fonctionnera ... Mais l’impression B ci-dessus générera une erreur d’encodage! Ce qui suit fonctionnera toutefois correctement:

print( u"bonjour, " + "fréd" ) # Call this "print C"

La conclusion à laquelle je suis arrivé (à titre provisoire) est que, si une chaîne spécifiée comme Unicode chaîne utilisant le & "; u &"; Le préfixe est soumis au mécanisme% -handling. Il semble impliquer l’utilisation du codage d’environnement par défaut, , que vous ayez défini ou non stdout pour la redirection!

La façon dont les gens traitent cela est une question de choix. Je souhaiterais qu'un expert Unicode dise pourquoi cela se produit, si je me trompe d'une manière ou d'une autre, quelle est la solution préférée à cela, que cela s'applique également à CPython , que ce soit en Python 3, etc., etc.

Sous Ubuntu 12.10 et GNOME Terminal, aucune erreur n’est générée lorsque le programme est imprimé sur stdout ou connecté à un canal pour d’autres programmes. Le codage de fichier et le codage de terminal sont tous deux UTF-8 .

$ cat a.py
# -*- coding: utf-8 -*-
print "åäö"
$ python a.py
åäö
$ python a.py | tee out
åäö

Quel système d'exploitation et émulateur de terminal utilisez-vous? J'ai entendu dire que certains de mes collègues rencontraient des problèmes similaires avec iTerm & Nbsp; 2 et OS X; iTerm & nbsp; 2 peut être le coupable.

Mise à jour: cette réponse est fausse - voir les commentaires pour plus de détails

J'ai rencontré ce problème dans une application héritée et il était difficile d'identifier où était imprimé ce qui était imprimé. Je me suis aidé avec ce hack:

# encoding_utf8.py
import codecs
import builtins


def print_utf8(text, **kwargs):
    print(str(text).encode('utf-8'), **kwargs)


def print_utf8(fn):
    def print_fn(*args, **kwargs):
        return fn(str(*args).encode('utf-8'), **kwargs)
    return print_fn


builtins.print = print_utf8(print)

En plus de mon script, test.py:

import encoding_utf8
string = 'Axwell Λ Ingrosso'
print(string)

Notez que cela modifie TOUS les appels à imprimer pour utiliser un codage. Votre console l’imprimera donc:

$ python test.py
b'Axwell \xce\x9b Ingrosso'
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top