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


143

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

デフォルトのエンコーディングの設定を探してみたところ、Python sys.setdefaultencodingは起動時に関数を削除してしまい、使用できないと言われています。

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


1
ブログの投稿The Illusive setdefaultencodingを参照してください。
djc

3
The best solution is to learn to use encode and decode correctly instead of using hacks.これはpython2で確かに可能でしたが、常にそうすることを覚えているか、一貫して独自のインターフェイスを使用するという犠牲を払っています。私の経験では、python2とpython3の両方で使用したいコードを記述する場合、これが非常に問題になることが示唆されています。
Righ

回答:


159

setdefaultencoding()から削除された関数を返す簡単な方法(ハック)を次に示しますsys

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

(Python 3.4以降の注意:ライブラリreload()にありimportlibます。)

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


5
その答えは既存のアプリケーションを実行するのに役立ちません(質問を解釈する1つの方法です)ので、私は反対票を投じました。正しい方法は、設定することですLC_CTYPE(または、アプリケーションで、正しく設定されているかどうかを確認し、意味のあるエラーメッセージで中止します)。
ibotty

@ibotty私はこの答えがハックであり、それを使用するのは危険であることに同意します。ただし、質問には答えます(「Pythonのデフォルトのエンコーディングを変更しますか?」)。Pythonインタープリターに対する環境変数LC_CTYPEの影響に関するリファレンスはありますか?
Eric O Lebigot、2015

まあ、それは言及しなかった、それは最初はハックです。それ以外は、危険な回答であり、それらが何であるかについての言及がない場合は役に立ちません。
ibotty

1
@EOLあなたは正しい。ただし、(Python 2および3で)preferredencodingに影響します:LC_CTYPE=C python -c 'import locale; print( locale.getpreferredencoding())'
ibotty

1
@ user2394901 sys.setdefaultencoding()の使用は常に推奨されていません!! そして、py3kのエンコーディングは "utf-8"に固定されており、それを変更するとエラーが発生します。
Marlon Abeykoon 2016年

70

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

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

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

export PYTHONIOENCODING=utf8


3
これは、私に何らかの違いをもたらした唯一のソリューションです。-私はDebian 7を使用していますが、ロケール設定が壊れています。ありがとう。
Pryo 2015

4
LC_CTYPE代わりに賢明なものに設定してください。それは他のすべてのプログラムも同様に幸せにします。
ibotty 2015年

5
Python3の大きなバグは、それPYTHONIOENCODING=utf8がデフォルトではないことです。これはスクリプトが壊れる原因になりますLC_ALL=C
Tino

Set LC_CTYPE to something sensible insteadこれは合理的な提案です。他の人のシステムでのみ機能するコードを配布しようとする場合、これはうまく機能しません。
Righ

DebianとRedhat OSはC.utf8ロケールを使用してより賢明なCを提供します。glibcアップストリームはそれを追加する作業をしているので、おそらくロケール設定を尊重するためにPythonを非難すべきではありません\…?
Arthur2e5 2018年

52

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

あなたのsitecustomize.pyをあなたのより高い場所に置くことができますPYTHONPATH

また、あなたはreload(sys).setdefaultencoding@EOLで試してみたいかもしれません

B)制御stdin.encodingstdout.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)または両方を使用できます


(python2のみ)個別ですが興味深いのは、ディスカッションfrom __future__ import unicode_literals参照して上記を拡張したものです
lukmdo

17

以降でPyDevは 3.4.1、デフォルトのエンコードはもう変更されていません。詳細については、このチケットを参照してください。

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


1
クリス、ありがとう。特に上記のマークTのコメントを考えると、あなたの答えは私にとって最も適切なようです。そして、主にEclipse / PyDevのユーザーではない人にとっては、自分でそれを理解することはできませんでした。
Sean

私は、世界的に(むしろ実行構成に一回以上)これを変更したいのですが、どのように考え出したていない-別のQ求めている:stackoverflow.com/questions/9394277/...
ティムDiggins

13

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

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

使用しないことをお勧めします(これまたはこれを確認してください)

私の場合、副作用が伴います。私はipythonノートブックを使用しています。コードを実行すると、「印刷」機能が機能しなくなります。私はそれに解決策があると思いますが、それでもハックを使用することは正しいオプションではないはずです。

多くのオプションを試した後、私のために機能したのは、同じコードをで使用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


8

それについて洞察に満ちたブログ投稿があります。

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がユニコード対応の場合)、「バイト」文字列をユニコード文字列で使用する場合は常に明示的にエンコードする必要があるという根本的な問題は解決されました。


4

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

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

sys.stdoutでprintunicode文字列とbeyond-asciiをstr(たとえばリテラルから)エンコードするエンコード問題を解決するために私が知っている最良の解決策は、次のことが可能です。必要に応じてオプションで許容:

  • ときにsys.stdout.encodingあるNoneいくつかの理由で、または存在しない、または誤って偽または「以下」標準出力端子またはストリームが本当に可能であるものよりも、正しい提供しようとする.encoding属性を。最後にsys.stdout & sys.stderr、翻訳するファイルのようなオブジェクトに置き換えます。

  • ターミナル/ストリームがまだ発生するすべてのUnicode文字をエンコードできない場合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 __name__ == '__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'スタイルユニコードエスケープを使用する。これは、asciiまたはUTF-8のプレーンな文字列リテラルを一貫して使用するPython 2またはPython 2 + 3のソースコードに注意を払うことで(anonbadgerの記事の内容にかかわらず)一貫して行うことができます。ユニコード変換し、モジュール間を移動するか、潜在的に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 __name__ == '__main__':
    sys.stdout = sys.stderr = SmartStdout()
    set_defaultencoding_globally('utf-8') 
    s = 'aouäöüфżß²'
    print s

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

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


4

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

このアプローチは、ファイルに似ていないsys.stdoutものに置き換えることで機能します(ただし、標準ライブラリの物だけを使用します)。これは基盤となるライブラリに問題を引き起こす可能性がありますが、フレームワークを通じてsys.stdoutの使用方法を適切に制御できる単純なケースでは、これは合理的なアプローチです。

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

3

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

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

1

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

私はsysのリロードを強制するアイデアが好きではなかったし、システムにPYTHONIOENCODING(直接Windows環境変数を試し、それをサイトパッケージの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 ' という行を追加することにより)。

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


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.