web-dev-qa-db-ja.com

pyスクリプトでsys.setdefaultencoding( "utf-8")を使用しないのはなぜですか?

これをスクリプトの上部で使用するpyスクリプトはほとんど見ていません。どのような場合に使用する必要がありますか?

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

ドキュメントに従って:これにより、デフォルトのASCIIからUTF-8などの他のエンコーディングに切り替えることができます。UTF-8は、Pythonランタイムが文字列バッファーをユニコード。

この関数は、Pythonが環境をスキャンするとき、Python起動時にのみ使用できます。システム全体のモジュールsitecustomize.pyで呼び出す必要があります。このモジュールが評価された後、setdefaultencoding()関数はsysモジュールから削除されます。

実際に使用する唯一の方法は、属性を戻すリロードハックを使用することです。

また、sys.setdefaultencoding()の使用は常に推奨されておらず、py3kではノーオペレーションになっています。 py3kのエンコーディングは「utf-8」に固定されており、変更するとエラーが発生します。

私は読むためのいくつかの指針を提案します:

133
pyfunc

tl; dr

答えはNEVER! (あなたが何をしているのかを本当に知っていない限り)

エンコード/デコードを適切に理解することで、9/10倍のソリューションを解決できます。

1/10人のロケールまたは環境が誤って定義されており、以下を設定する必要があります。

PYTHONIOENCODING="UTF-8"  

コンソール印刷の問題を修正するための環境で。

それは何をするためのものか?

sys.setdefaultencoding("utf-8") (再使用を避けるために取り消し線で)Python 2.xがUnicode()をstr()に変換する必要があるとき(およびその逆)に使用されるデフォルトのエンコード/デコードを変更します。与えられた。つまり:

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

Python 2.xでは、デフォルトのエンコーディングはASCIIに設定されており、上記の例は次のように失敗します。

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 0: ordinal not in range(128)

(私のコンソールはUTF-8として構成されているため、"€" = '\xe2\x82\xac'、したがって\xe2の例外)

または

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

sys.setdefaultencoding("utf-8") これらはmeで機能しますが、UTF-8を使用していない人には必ずしも機能しません。 ASCIIのデフォルトは、エンコードの前提がコードに焼き付けられないことを保証します

コンソール

sys.setdefaultencoding("utf-8") また、コンソールに文字を出力するときに使用されるsys.stdout.encodingを修正するように見えるという副作用もあります。 Pythonは、ユーザーのロケール(Linux/OS X/Un * x)またはコードページ(Windows)を使用してこれを設定します。時々、ユーザーのロケールが壊れていて、console encodingを修正するためにPYTHONIOENCODINGが必要なだけです。

例:

$ 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"
€

何が悪いの sys.setdefaultencoding( "utf-8")

デフォルトのエンコードはASCIIであるとの理解のもと、人々はPython 2.xに対して16年間開発を続けてきました。 UnicodeError例外処理メソッドは、非ASCIIを含むことが判明した文字列の文字列からUnicodeへの変換を処理するために記述されています。

から 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"))

Defaultencodingを設定する前は、このコードはASCIIエンコードの「Å」をデコードできず、例外ハンドラーを入力してエンコードを推測し、適切にUnicodeに変換していました。印刷:Angstrom(Å®)がビジネスを運営します。 defaultencodingをutf-8に設定すると、コードはbyte_stringをutf-8として解釈できるため、データを破壊し、代わりにこれを返します。Angstrom(Ů)はビジネスを実行します。

定数を変更すると、依存するモジュールに劇的な影響を与えます。コードに出入りするデータを修正することをお勧めします。

問題の例

次の例では、defaultencodingの設定がUTF-8の根本的な原因ではありませんが、問題がマスクされる方法と、入力エンコーディングが変更されたときにコードが明白な方法で中断する方法を示します: nicodeDecodeError: ' utf8 'コーデックは位置3131のバイト0x80をデコードできません:無効な開始バイト

52
#!/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)

シェルで動作し、sdtoutではなくsdtoutに送信するため、stdoutに書き込むための1つの回避策です。

Sys.stdout.encodingが定義されていない場合、つまり、stdoutに書き込むために最初にPYTHONIOENCODING = UTF-8をエクスポートする必要がある場合、実行されない他のアプローチを作成しました。

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)


そのため、同じ例を使用します。

export PYTHONIOENCODING=UTF-8
./test.py > output.txt

働くでしょう

18
Sérgio
  • 最初の危険はreload(sys)にあります。

    モジュールをリロードすると、実行時にモジュールのtwoコピーが実際に取得されます。古いモジュールは、他のすべてと同じPythonオブジェクトであり、それへの参照がある限り存続します。したがって、オブジェクトの半分は古いモジュールを指し、半分は新しいモジュールを指します。何らかの変更を加えた場合、ランダムなオブジェクトが変更を認識しない場合、それが表示されることはありません。

    (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>
    
  • さて、sys.setdefaultencoding()固有

    影響を受けるのは暗黙の変換str<->unicode だけです。現在、utf-8は地球上で最も安全なエンコーディングであり(ASCIIおよびすべてと下位互換性があります)、変換は「正常に動作します」、何が問題になる可能性がありますか?

    まあ、何でも。それは危険です。

    • ASCII以外の入力に対してスローされるUnicodeErrorに依存するコードや、エラーハンドラーでトランスコーディングを実行するコードが存在する可能性があります。これにより、予期しない結果が生成されます。そしてすべてのコードはデフォルト設定でテストされているため、ここでは「サポートされていない」領域に厳密になります、そしてコードの動作について保証する人はいません。
    • システム上のすべてがUTF-8を使用しているわけではない場合、トランスコーディングは予期しない結果または使用できない結果を生成する可能性があります Python 2には複数の独立した「デフォルト文字列エンコーディング」があるため (プログラムは、顧客の機器で、顧客のために機能する必要があることを忘れないでください。)
      • 繰り返しになりますが、最悪のことは変換が暗黙的であるため、とは決してわかりません。-いつ、どこで起こるかわかりません。(Python Zen、koan 2 ahoy! )コードが1つのシステムで動作し、別のシステムで動作しなくなる理由(およびその場合)は決してわかりません。 (さらに良いことに、IDEで動作し、コンソールで壊れます。)
3
ivan_pozdeev