標準出力とリダイレクトのエンコーディング

lxmlで取得したデータを、print で出力させて
リダイレクトでファイルに保存しようとしたら
”UnicodeEncodeError"が発生してはまりまくったのでメモ


詳しくは、[Python-ml-jp 3250] で書かれています。
とても分かりやすいので、リンク先の参照をおすすめします。
http://www.python.jp/pipermail/python-ml-jp/2005-March/003247.html


発生していた問題:
1. unicodeオブジェクトをいきなりprint文で印字しようとした。
2. その結果、Pythonの「暗黙のエンコード」が起きた。
3. デフォルトのエンコード名が、"None"と判定された。
4. Python側で、"None"の代わりに"ascii"を使用してエンコードした。
5. ”UnicodeEncodeError"が発生した。


デフォルトのエンコード名は、"sys.stdout.encoding"で取得できます。
標準出力の場合は、正しい値が取得できますが、リダイレクトをさせると
この値が変わってしまうため、問題となりました。

確認用プログラム

# coding: utf-8 
# vim: fileencoding=utf-8 

if __name__ == '__main__':
    import sys
    print sys.stdout.encoding
    print sys.getfilesystemencoding()

実効結果

[kuma8@~]$ python stdout_encode.py 
UTF-8
UTF-8
[kuma8@~]$ python stdout_encode.py > a
[kuma8@~]$ cat a
None
UTF-8


unicodeオブジェクトをprint文で印字させる必要があるときは、
明示的にエンコードをさせるか、unicode→string 変換が
起こらないように処置するのが無難なようです。

# unicode→string 変換をさせない
print repr(str)
# 明示的なエンコード
print str.encode(sys.getfilesystemencoding())