Python 2でデフォルトの出力エンコーディングを設定することはよく知られているイディオムです:
_sys.stdout = codecs.getwriter("utf-8")(sys.stdout)
_
これは、UTF-8で出力をエンコードするコーデックライターで_sys.stdout
_オブジェクトをラップします。
ただし、sys.stdout.write()
にはstr
が必要ですが、エンコードの結果はbytes
であるため、この手法はPython 3では機能しません。 codecs
がエンコードされたバイトを元の_sys.stdout
_に書き込もうとするとエラーが発生します。
Python 3?でこれを行う正しい方法は何ですか?
Python 3.7から reconfigure()
で標準ストリームのエンコードを変更できます:
sys.stdout.reconfigure(encoding='utf-8')
errors
パラメーターを追加して、エンコードエラーの処理方法を変更することもできます。
Python 3.1はio.TextIOBase.detach()
を追加しました。 _sys.stdout
_ のドキュメントに注記があります:
標準ストリームはデフォルトでテキストモードになっています。これらにバイナリデータを書き込んだり読み取ったりするには、基になるバイナリバッファを使用します。たとえば、
stdout
にバイトを書き込むには、sys.stdout.buffer.write(b'abc')
を使用します。io.TextIOBase.detach()
ストリームを使用すると、デフォルトでバイナリにすることができます。この関数は、stdin
およびstdout
をバイナリに設定します。_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())
_
同じエラーの解決策を探しているときにこのスレッドを見つけましたが、
すでに提案されているものの代替ソリューションは、PYTHONIOENCODING
環境変数を設定することですbeforePython開始、私の使用のために-これは、Pythonが初期化された後にsys.stdout
を交換するよりも問題が少ないです。
PYTHONIOENCODING=utf-8:surrogateescape python3 somescript.py
Pythonコードを編集する必要がないという利点があります。
他の答えはcodecs
の使用を推奨しているように見えますが、open
は私には役立ちます:
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"
で実行しても機能します。
Python 2でデフォルトの出力エンコーディングを設定することはよく知られているイディオムです
ほら!それはPython 2?の有名なイディオムですか?それは私にとって危険な間違いのように見えます。
確かに、バイナリをstdoutに書き込もうとするスクリプトを台無しにします(たとえば、イメージを返すCGIスクリプトの場合に必要になります)。バイトと文字はまったく異なる動物です。 charsのみを受け取るものでバイトを受け入れるように指定されたインターフェイスを、モンキーパッチすることはお勧めできません。
一般に、CGIおよびHTTPはバイトを明示的に使用します。 sys.stdoutにのみバイトを送信する必要があります。 In Python 3は、sys.stdout.buffer.write
バイトを直接送信します。 charset
パラメータと一致するようにページコンテンツをエンコードすることは、アプリケーション内でより高いレベルで処理する必要があります(バイナリではなくテキストコンテンツを返す場合)。また、これはprint
がCGIにとってもはや役に立たないことを意味します。
(混乱を増すために、wsgirefのCGIHandlerはごく最近までpy3kで壊れていたため、WSGIをCGIにそのようにデプロイすることはできませんでした。PEP3333およびPython 3.2
detach()
を使用すると、インタープリターは、終了する直前にstdoutを閉じようとしたときに警告を出力します。
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')
(そしてもちろん、default_out
代わりにstdout。)
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のビルドでの別の問題です。