372 votes

Réglage de l'encodage correct lorsque la tuyauterie stdout en python

Lorsque la tuyauterie de sortie d'un programme en python, l'interpréteur python devient confus au sujet de l'encodage et il définit à Aucun. Cela signifie qu'un programme comme celui-ci:

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

fonctionne correctement lorsqu'il est exécuté normalement, mais ne parviennent pas à:

UnicodeEncodeError: 'ascii' codec can't encode character u'\xa0' in position 0: ordinal not in range(128)

lorsque utilisé dans un tuyau séquence.

Quelle est la meilleure façon de faire ce travail si la tuyauterie? Je peux juste dire qu'il utilise le codage de la coquille/système de fichiers/tout ce qui est aide?

Les suggestions que j'ai vu jusqu'à présent est de modifier votre site.py directement, ou coder en dur les defaultencoding à l'aide de ce hack:

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

Est-il une meilleure façon de faire de la tuyauterie de travail?

170voto

nosklo Points 75862

Votre code fonctionne lorsque vous exécutez un script parce que python code pour la sortie de tout codage de votre application terminal. Si vous êtes à la tuyauterie, vous devez coder vous-même.

Une règle de base: Toujours utiliser l'unicode en interne. décoder ce que vous recevez, de coder ce que vous envoyez.

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

Un autre exemple didactique est un programme en python pour convertir entre iso8859-1 et utf-8, tout en faisant en majuscules 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)

Le réglage par défaut du système de codage est une mauvaise idée, car certains modules et bibliothèques que vous utilisez peut compter sur le fait que c'est l'ascii. Ne pas le faire.

168voto

Craig McQueen Points 13194

Tout d'abord, au sujet de cette solution:

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

C'est pas pratique explicitement d'impression avec un encodage à chaque fois. Ce serait répétitif et sujette à erreur.

Une meilleure solution est de changer de sys.stdout au début de votre programme, pour encoder avec un encodage sélectionné. Voici une solution que j'ai trouvé sur Python: Comment est-sys.la sortie standard stdout.l'encodage choisi?, en particulier, un commentaire de "toka":

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

140voto

daveagp Points 1021

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

Tl;dr de le post de blog:

import sys, locale, os
print(sys.stdout.encoding)
print(sys.stdout.isatty())
print(locale.getpreferredencoding())
print(sys.getfilesystemencoding())
print(os.environ["PYTHONIOENCODING"])
print(chr(246), chr(9786), chr(9787))

vous donne

utf_8
False
ANSI_X3.4-1968
ascii
utf_8
ö  ☻

64voto

Sérgio Points 854
export PYTHONIOENCODING=utf-8

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

ce que nous pouvons faire est de vérifier si n'est pas de réglage et de dire à l'utilisateur de définir avant d'appeler le script 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)

2voto

jno Points 31

J'ai pu "automatiser" il 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 de faire une boucle infinie si ce "setenv" échoue.

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