file.write() 時の UnicodeError 対策
sys.stdout.write(u'ほげ')
などとした際に UnicodeError
を食らわないための対策。
Cygwin 1.7.9-1, Python 2.6.5-2 で調査したものです。Windows環境、およびPython3については触れません。また、ソースコードのエンコーディング((# coding: utf-8
のようなコメントのこと。なお、-c
オプションによるワンライナのエンコーディングは常に latin-1 と仮定される模様。))は適切に設定されているものとします。
最も簡単なのはUnicode文字列を一切使わず、全てByte文字列で処理することです。ただしこれだと文字列処理が必要な場合面倒なことになるので、やはりUnicode文字列のみを使いたいというケースが多いと思います。
結論から言うと、スクリプトの冒頭で以下のようにするのがよさそうです:((errors='replace'
を指定するのは、出力エンコーディングで表現できない文字が含まれていた場合に UnicodeEncodeError
となるのを避けるため。)) ((ただし、このように codecs.StreamWriter
でラップした場合、write()
にByte文字列をそのまま渡すことはできなくなるので注意(常にUnicode文字列に変換してから処理され、このとき変換に失敗すると UnicodeDecodeError
となる)。))
ENC_LOCALE = locale.getpreferredencoding() sys.stdout = codecs.getwriter(ENC_LOCALE)(sys.stdout, errors='replace') sys.stderr = codecs.getwriter(ENC_LOCALE)(sys.stderr, errors='replace')
sitecustomize.py 内で sys.setdefaultencoding()
するのは避けるべきです。移植性を損なう上に、デフォルトエンコーディングに依存するライブラリが存在する可能性もあるからです。これは最後の手段とみなすべきでしょう。
以下はPythonのエンコーディング決定の仕組みと、Byte文字列/Unicode文字列の自動変換についてのメモ。
エンコーディング決定の仕組み
sys.getdefaultencoding()
デフォルトで 'ascii'
。ただし sitecustomize.py 内で sys.setdefaultencoding()
による設定が可能(前述の通り、これは最後の手段)。
locale.getpreferredencoding()
, sys.getfilesystemencoding()
LC_CTYPE
環境変数に従う。LC_CTYPE=C
の場合、'ANSI_X3.4-1968'
。
標準ストリーム(sys.stdin
, sys.stdout
, sys.stderr
)の encoding
属性
[http://docs.python.org/using/cmdline.html#envvar-PYTHONIOENCODING:title=PYTHONIOENCODING]
環境変数が存在すれば常にそれに従う。さもなくば
- 接続先が端末ならば
locale.getpreferredencoding()
に従う - 接続先が非端末(リダイレクトなど)ならば
None
なお、標準ストリームのUnicodeエラーハンドラ(errors
属性)は [http://docs.python.org/using/cmdline.html#envvar-PYTHONIOENCODING:title=PYTHONIOENCODING]
環境変数が存在すればそれに従う。さもなくば None
。