スポンサーサイト
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
【--/--/-- --:--】 | スポンサー広告 | page top↑
python3.0におけるファイルのデフォルトencoding
年をまたいで、Pythonいじって遊んでいたのですが、どうもPython3.0でのMacOSXにおけるバグっぽいものを見つけてしまったようなので、メモ程度に。

fileを読み込むときのデフォルトのコーデックが、なぜかshift_jisになってしまっているようです。
ちなみに、XPだと普通に動きますし、MacでもファイルをShift_jisで保存すればそのまま動きます。
makeで入れたpythonですが、OSは10.4でも10.5でも同じでした。

Python 3.0 (r30:67503, Jan 1 2009, 00:12:01)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> f = open('temp.txt')
>>> f.readline()
Traceback (most recent call last):
File "", line 1, in
File "/Library/Frameworks/Python.framework/Versions/3.0/lib/python3.0/io.py", line 1813, in readline
while self._read_chunk():
File "/Library/Frameworks/Python.framework/Versions/3.0/lib/python3.0/io.py", line 1562, in _read_chunk
self._set_decoded_chars(self._decoder.decode(input_chunk, eof))
File "/Library/Frameworks/Python.framework/Versions/3.0/lib/python3.0/io.py", line 1295, in decode
output = self.decoder.decode(input, final=final)
UnicodeDecodeError: 'shift_jis' codec can't decode bytes in position 8-9: illegal multibyte sequence
>>>
>>> f.close()
>>> f = open('temp.txt',encoding='utf=8')
>>> f.readline()
'あいうえお\n'
>>> f.close();

temp.txtは、UTF-8で保存されており、これをShift_jisにすると読めるので、おそらく組み込み関数openのデフォルトのencodingが、なぜかshift_jisになっていることが問題かと思われます。
本家のバグレポートには、それっぽいエントリーはなかったのですが、報告するにはまだ調べが足りないかな。。。
まあ、まだ3.0なので、次のバージョンでこっそり直っていてくれると嬉しいですが。

2009/1/4訂正
Windowsでは動くと書きましたが、どうやら勘違い。
やはり、Vista(SP1)とXP(SP3)ともに、デフォルトのfile読込時のcodecがcp932になっているようです。

仕方ないので、組み込み関数openのソースを見てみました。
io.pyのopen関数の中でTextIOWrapperを呼んでいるのですが、ここに出てくる
os.device_encoding()
が、どうやらいけないのかな?
3.0から導入されたメソッドっぽいですが、File Descriptorの番号に応じてencodingを返すようです。
ユーザーがファイルを開くと、3から順に番号が付けられると思うのですが、そのときは、encodingは返ってこないので、その下の、
encoding = locale.getpreferredencoding()
が、結局呼ばれる事になります。

class TextIOWrapper(TextIOBase):
 _CHUNK_SIZE = 128

 def __init__(self, buffer, encoding=None, errors=None, newline=None,line_buffering=False):
  if newline not in (None, "", "\n", "\r", "\r\n"):
   raise ValueError("illegal newline value: %r" % (newline,))
  if encoding is None:
   try:
    encoding = os.device_encoding(buffer.fileno())
   except (AttributeError, UnsupportedOperation):
    pass
   if encoding is None:
    try:
     import locale
    except ImportError:
     # Importing locale may fail if Python is being built
     encoding = "ascii"
    else:
     encoding = locale.getpreferredencoding()

というわけで、これが、MacOSX10.4では、
>>> locale.getpreferredencoding()
'X-MAC-JAPANESE'
となっていて、
>>> locale.getdefaultlocale()
(None, 'X-MAC-JAPANESE')
と、同じ。この名前が、Shift_JISにバインドされています。所謂、純粋なShift_JISで、Windows-31J(cp932)とは違います。
ちなみに、windowsXPでは、おなじメソッドが今度は、'cp932'を返すので、ファイルを開くときにcodecがおかしくなる理由が何となくわかりました。
Ubuntuだとすべて、UTF-8と返ってきて、問題まったくなし。んー、テストがLinuxで行われているのか?
なんか、バグじゃなくて仕様のような気もしてきましたが、MacもWinも、できればデフォルトでUTF-8にして欲しいなー。

と思っていたら、やっぱり仕様でした。
ちゃんと、ドキュメントを読もう、という話です・・・

There is a platform-dependent default encoding, which on Unixy platforms can be set with the LANG environment variable (and sometimes also with some other platform-specific locale-related environment variables).
What's new in Python3.0より。

なんと、環境ごとに気を遣ってくれているようです。(そんなんことしてくれなくていいのに・・・)

というわけで、環境変数をいじります。
Macの場合、LANGは、Ja_JP.UTF-8になっているので、
__CF_USER_TEXT_ENCODING="0x1F5:0x08000100:14"
export __CF_USER_TEXT_ENCODING
とします。
__CF_USER_TEXT_ENCODINGの設定方法は、いまひとつ掴みきれていませんが、:で挟まれた二つ目の引数が、1になっているところを、UTF-8を表す、0x08000100に変更すると、ファイルのデフォルトcodecがUTF-8になります。
windowsは、だめですデフォルトのシステムロケールを変更できるのかどうかよくわかりません。
要調査。知っている人いたら教えてください。
スポンサーサイト

テーマ:プログラミング - ジャンル:コンピュータ

【2009/01/01 00:29】 | Python | トラックバック(1) | コメント(0) | page top↑
<<すごいページ(Pythonの内部的な仕組み) | ホーム | MacでいろいろなPythonのバージョンをインストールする>>
コメント
コメントの投稿














管理者にだけ表示を許可する

トラックバック
トラックバックURL
→http://tanopy.blog79.fc2.com/tb.php/34-c499cf8e
この記事にトラックバックする(FC2ブログユーザー)
[Python]こんにちは世界に一苦労
Pythonの3.0を試してみたら日本語表示でドモった。エンコーディングがutf-8のhoge.txtというファイルの中身を表示させてみる。環境はMacOSX(10.4.11)とPython3.0.1。 とりあえずやってみたら >>> fp = open("hoge.txt", "r") >>> h blankblankの日記【2009/03/04 00:42】
| ホーム |
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。