2010-12-07 6 views
35

は、周知のイディオムである:Python 3でsys.stdoutエンコーディングを設定するには? Pythonの2のデフォルトの出力エンコーディングを設定

sys.stdout = codecs.getwriter("utf-8")(sys.stdout) 

これは、UTF-8で出力を符号化するコーデックライタのsys.stdoutオブジェクトをラップします。 sys.stdout.write()strを期待するが、符号化の結果はbytesあり、codecsが元sys.stdoutに符号化されたバイトを書き込みしようとするとエラーが発生するため

しかし、この技術は、Python 3で動作しません。

これをPython 3で行う正しい方法は何ですか?

+0

2to3は、このような質問に役立つツールです。 –

+0

@dan_waterworth:私はそれを前に試してみることは考えていませんでしたが、今は '2to3'を試してみました。 –

+3

新しいコードが機能しない場合は、これをバグとして追加することをお勧めします。 –

答えて

30

のPython 3.1はsys.stdoutのドキュメント内のノートで、io.TextIOBase.detach()を追加しました:

標準ストリームは、デフォルトではテキストモードです。これらにバイナリデータを書き込みまたは読み込むには、基礎となるバイナリバッファを使用します。たとえば、stdoutにバイトを書き込むには、sys.stdout.buffer.write(b'abc')を使用します。 io.TextIOBase.detach()ストリームを使用すると、デフォルトでバイナリにすることができます。この関数は、バイナリにstdinstdout設定:したがって

def make_streams_binary(): 
    sys.stdin = sys.stdin.detach() 
    sys.stdout = sys.stdout.detach() 

、以降のPythonの3.1に対応するイディオム:

sys.stdout = codecs.getwriter("utf-8")(sys.stdout.detach()) 
+5

私は'PYTHONIOENCODING'を使う。さもなければ 'io.TextIOWrapper'が改行を適切に処理する' codecs'よりも優れた選択肢かもしれません。 – jfs

+0

これは 'sys.stdout'の動作を完全に変更します。 – Sebastian

7

sys.stdoutのはそのためのPython 3.テキストモードでありますそれに直接unicodeを書いてください。Python 2のイディオムはもはや必要ありません。

これは、Python 2で失敗する

>>> import sys 
>>> sys.stdout.write(u"ûnicöde") 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
UnicodeEncodeError: 'ascii' codec can't encode character u'\xfb' in position 0: ordinal not in range(128) 

しかし、それは、Python 3でちょうどダンディ作品:

>>> import sys 
>>> sys.stdout.write("Ûnicöde") 
Ûnicöde7 

今、あなたのPythonがあなたのstdoutsエンコーディングが実際に何であるか知っていない場合それは別の問題です。Pythonのビルドにはおそらくそうです。 Pythonの2のデフォルトの出力エンコーディングを設定

+2

私のコンテキストは、Apacheの下でCGIとしてPythonスクリプトを実行していましたが、デフォルトの出力エンコーディングは私が必要としていたものではありませんでした(私はUTF- 8)。スクリプトが外部設定(PYTHONIOENCODINGなどの環境変数など)に頼るのではなく、出力が正しいエンコーディングになっていることを確認する方が良いと思います。 –

+1

さらに、プロセス通信にstdoutを使用することは大きな間違いです。この場合、CGIを使用するよりも選択肢がないかもしれないことはわかっていますが、それはあなたの責任ではありません。 :-) –

+0

'sys.stdout'はPython 2の*バイナリ*ファイルとPython 3の* text *ファイルですが、Python 2の例は失敗すると思いますが、Unicode文字列' u "ûnicöde" ' 'sys.stdout.write'メソッドで暗黙的にエンコードされた文字は、ASCII範囲外の文字を持ちます。 'LC_CTYPE'、' LANG'または 'PYTHONIOENCODING'環境変数を、Unicode文字列のすべての文字を持つエンコーディングに変更すると、エラーは発生しません。 (私はPython 2.7を試しました。) – Maggyero

16

は、よく知られているイディオム

イークです!これはPython 2のよく知られたイディオムですか?それは私に危険なミスのように見えます。

stdoutにバイナリを書き込もうとするスクリプトを間違えてしまうことがあります(たとえば、画像を返すCGIスクリプトの場合に必要です)。バイトと文字は全く異なる動物です。文字だけを取るものでバイトを受け入れるように指定されたインタフェースをサルパッチするのは良い考えではありません。

一般にCGIとHTTPはバイトで明示的に動作します。あなたはバイトをsys.stdoutに送るべきです。 Python 3では、sys.stdout.buffer.writeを使用して直接バイトを送信することを意味します。 charsetパラメータに一致するようにページコンテンツをエンコードすることは、アプリケーションのより高いレベルで処理する必要があります(バイナリではなくテキストコンテンツを返す場合)。これはまた、printがCGIにはうってつけでないことを意味します。

(混乱に追加するには、wsgirefのCGIHandlerのは不可能そのようにCGIためにWSGIを展開すること、ごく最近までpy3kに切断された。PEP 3333とPython 3.2ではこれが最終的に実行可能である。)

+0

このコメントは、3.3および今後リリースされる3.4 Pythonリリースに関して更新する必要があります。ありがとうございました – soshial

18

IこれはPythonがされた後sys.stdoutをスワップあまりトラブルがある -

すでに示唆したものに代替ソリューションを Pythonが私の使用を開始し、変数 PYTHONIOENCODING環境を設定することである

、同じエラーの解決策を探している間、このスレッドを見つけました初期化済み:

PYTHONIOENCODING=utf-8:surrogateescape python3 somescript.py 

Pythonコードを編集する必要がないという利点があります。 detach()を使用して

+0

主にPYTHONIOENCODING = utf-8が何時間もの検索の後で私の問題を解決したために親指を上げました。 – theeggman85

5

は、それが終了直前に標準出力を閉じようとしたときに警告を表示するには、インタプリタが発生します。

Exception ignored in: <_io.TextIOWrapper mode='w' encoding='UTF-8'> 
ValueError: underlying buffer has been detached 

は代わりに、これは私のためにうまく働いた:

default_out = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') 

(そして、のもちろん、stdoutの代わりにdefault_outに書き込んでください)

15

他の回答はcodecsですが、私のための点の作品:

import sys 
sys.stdout = open(sys.stdout.fileno(), mode='w', encoding='utf8', buffering=1) 
print("日本語") 
# Also works with other methods of writing to stdout: 
sys.stdout.write("日本語\n") 
sys.stdout.buffer.write("日本語\n".encode()) 

これは私がPYTHONIOENCODING="ascii"でそれを実行した場合でも動作します。

関連する問題