web-dev-qa-db-ja.com

Pythonのデフォルトエンコーディングを変更しますか?

コンソールからアプリケーションを実行すると、 Python で多くの「エンコードできない」および「デコードできない」問題が発生します。しかし EclipsePyDev IDEでは、デフォルトの文字エンコーディングは TF-8 に設定されており、問題ありません。

デフォルトのエンコーディングを設定するために検索しましたが、人々はPythonが起動時にsys.setdefaultencoding関数を削除し、それを使用できないと言います。

それで、それに対する最善の解決策は何ですか?

120
Ali Nadalizadeh

以下は、sysから削除されたsetdefaultencoding()関数を返す簡単なメソッド(ハック)です。

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

これは安全なことではありませんが:Pythonのときにsys.setdefaultencoding()sysから意図的に削除されるため、これは明らかにハックです開始します。それを再度有効にしてデフォルトのエンコーディングを変更します デフォルトであるASCIIに依存するコードを壊すことができます (このコードはサードパーティである可能性があり、一般に修正が不可能または危険になります)。

141
Eric O Lebigot

スクリプトの出力をパイプ/リダイレクトしようとしたときにこのエラーが発生した場合

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)

コンソールでPYTHONIOENCODINGをエクスポートして、コードを実行するだけです。

export PYTHONIOENCODING=utf8

58
iman

A)sys.getdefaultencoding()の出力を制御するには:

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

ascii

それから

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

そして

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

utf-16-be

PYTHONPATHsitecustomize.pyを高くすることができます。

また、 reload(sys).setdefaultencoding by @EOLを試してみたいかもしれません

B)stdin.encodingおよびstdout.encodingを制御するには、PYTHONIOENCODINGを設定します:

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

ascii ascii

それから

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

utf-16-be utf-16-be

最後に:A)またはB)またはboth!

50
lukmdo

PyDev 3.4.1以降、デフォルトのエンコーディングは変更されていません。詳細については this ticket をご覧ください。

以前のバージョンの解決策は、PyDevがデフォルトのエンコーディングとしてUTF-8で実行されないようにすることです。 Eclipseで、ダイアログ設定を実行します(正しく覚えていれば「実行構成」)。共通タブでデフォルトのエンコードを選択できます。これらのエラーを「初期」にしたい場合はUS-ASCIIに変更してください(つまり、PyDev環境で)。 この回避策の元のブログ投稿 も参照してください。

17
ChristopheD

Python2(およびpython2のみ)に関して、以前の回答のいくつかは、次のハックの使用に依存しています。

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

使用しないことをお勧めします(チェック this または this

私の場合、副作用があります。ipythonノートブックを使用しています。コードを実行すると、「print」関数が機能しなくなります。私はそれに対する解決策があると思いますが、それでもハックを使用することは正しい選択肢ではないはずです。

多くのオプションを試した後、私のために働いたものは、sitecustomize.pyで同じコードを使用することでした。コードの一部はそのモジュールを評価した後、setdefaultencoding関数はsysから削除されます。

そのため、解決策は、ファイル/usr/lib/python2.7/sitecustomize.pyにコードを追加することです。

import sys
sys.setdefaultencoding('UTF8')

Virtualenvwrapperを使用する場合、編集するファイルは~/.virtualenvs/venv-name/lib/python2.7/sitecustomize.pyです。

そして、pythonノートブックとcondaで使用すると、~/anaconda2/lib/python2.7/sitecustomize.pyになります。

13
kiril

それについての洞察力に富んだブログ投稿があります。

https://anonbadger.wordpress.com/2015/06/16/why-sys-setdefaultencoding-will-break-code/ を参照してください。

以下にその内容を言い換えます。

文字列のエンコードに関してそれほど強く型付けされていなかったpython 2では、異なるエンコードされた文字列に対して操作を実行でき、成功します。例えば。以下はTrueを返します。

u'Toshio' == 'Toshio'

これは、sys.getdefaultencoding()でエンコードされたすべての(通常の、接頭辞なしの)文字列に適用され、デフォルトではasciiになりますが、他の文字列には適用されません。

デフォルトのエンコーディングは、site.pyでシステム全体で変更されることを意図していましたが、他の場所では変更されませんでした。ユーザーモジュールに設定するためのハック(ここでも説明します)は、ハッキングであり、ソリューションではありません。

Python 3はシステムエンコーディングをデフォルトのutf-8に変更しましたが(LC_CTYPEがユニコード対応の場合)、基本的な問題は、ユニコード文字列で使用されるたびに「バイト」文字列を明示的にエンコードする要件で解決されました。

8
ibotty

最初:reload(sys)と、出力ターミナルストリームの必要性に関するランダムなデフォルトエンコーディングの設定は、悪い習慣です。 reloadは多くの場合、環境に応じて適切に配置されているsysの内容を変更します。 sys.stdin/stdoutストリーム、sys.excepthookなど.

Stdoutのエンコードの問題を解決する

Sys.stdoutでのprint 'ingユニコード文字列およびASCIIを超えるstrのエンコード問題(リテラルからなど)を解決するために知っている最良の解決策は、次のとおりです。必要に応じてオプションで許容:

  • 何らかの理由でsys.stdout.encodingNoneであるか、存在しないか、誤ってfalseであるか、stdout端末またはストリームが実際に可能なものよりも「少ない」場合、正しい.encoding属性を指定してください。最後に、sys.stdout & sys.stderrをファイルのような翻訳オブジェクトに置き換えることにより。

  • ターミナル/ストリームが発生するすべてのユニコード文字をまだエンコードできない場合、およびそのためにprintを壊したくない場合は、ファイルに似たオブジェクトを変換するときにエンコードを置換する動作を導入できます。

次に例を示します。

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

Python 2/2 + 3コードでのASCIIを超えたプレーン文字列リテラルの使用

グローバルなデフォルトのエンコーディングを(UTF-8のみに)変更する唯一の正当な理由は、アプリケーションに関するものだと思いますソースコード決定-I/Oストリームエンコーディングの問題ではなく、常にu'string'スタイルのUnicodeエスケープを使用せずに、文字列リテラルをコードに変換します。これはPython 2またはPython 2 + 3のソースコードベースを処理することにより、(anonbadgerの記事に書かれていることにもかかわらず)かなり一貫して行うことができます。 asciiまたはUTF-8プレーン文字列リテラルを一貫して使用します-それらの文字列が潜在的にサイレントUnicode変換を受け、モジュール間を移動するか、潜在的にstdoutに移動する限り。そのためには、「# encoding: utf-8」またはascii(宣言なし)をお勧めします。 chr#127(今日ではまれです)を超えるASCIIデフォルトエンコーディングエラーに致命的に依存しているライブラリを変更またはドロップします。

そして、上記のSmartStdoutスキームに加えて、アプリケーションの起動時に(および/またはsitecustomize.pyを介して)このようにします-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

このように、文字列リテラルとほとんどの操作(文字の繰り返しを除く)は、Unicode変換をPython3のみのように考えることなく快適に動作します。もちろん、ファイルI/Oは、Python3の場合と同様に、エンコードに関して常に特別な注意が必要です。

注:プレーン文字列は、utf-8からSmartStdoutのUnicodeに暗黙的に変換されてから、出力ストリームエンコーディングに変換されます。

3
kxr

これで問題が解決しました。

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

これは、python2python3の両方と互換性があり、常に生成されるコードを生成するために使用したアプローチですutf8出力。他の場所でこの答えを見つけましたが、ソースを思い出せません。

このアプローチは、sys.stdoutファイルのようなものではありませんに置き換えます(ただし、標準ライブラリ内のもののみを使用します)。これは基礎となるライブラリに問題を引き起こす可能性がありますが、sys.stdout outがフレームワークでどのように使用されるかを適切に制御できる単純な場合、これは合理的なアプローチです。

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

これは、(1)Windowsプラットフォームで(2)Python 2.7を実行し、(3)素敵なソフトウェア(つまり、あなたによって書かれていないためすぐにエンコード/デコード印刷操作の候補)は、IDLE環境で「きれいなユニコード文字」を表示しません(Pythonwinはユニコードを印刷します)。たとえば、Stephan Boyerが教育学の証明者からの出力で使用するきちんとしたFirst Order Logicシンボル First Order Logic Prover

システムを強制的にリロードするという考えが気に入らず、システムにPYTHONIOENCODINGなどの環境変数の設定に協力させることができませんでした(直接Windows環境変数を試し、site-packagesのsitecustomize.pyにそれを1つとしてドロップしました)ライナー= 'utf-8')。

そのため、成功への道をハッキングする意思がある場合は、通常IDLEディレクトリに移動します。「C:\ Python27\Lib\idlelib」ファイルIOBinding.pyを見つけます。そのファイルのコピーを作成し、別の場所に保存して、選択したときに元の動作に戻すことができるようにします。エディター(例:IDLE)でidlelibのファイルを開きます。このコード領域に移動します。

# 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

言い換えると、エンコーディング変数をlocale.getdefaultlocaleに等しくしていた 'try'に続く元のコード行をコメントアウトします(これにより、不要なcp1252が得られるため)、代わりにブルートフォースで 'utf-8'にします(行 'encoding =' utf-8)を追加しますように)。

これはstdoutへのIDLE表示にのみ影響し、ファイル名などに使用されるエンコーディング(以前のファイルシステムエンコーディングで取得された)には影響しないと思います。後でIDLEで実行する他のコードに問題がある場合は、IOBinding.pyファイルを元の変更されていないファイルに置き換えるだけです。

1
Dalton Bentley