From the Southern Hemisphere

From the Southern Hemisphere

南半球に移住したプログラマの日々

【Python】UnicodeDecodeError の対応

こんにちは、ピコピコくんです。
今日はPython スクリプト実行時に発生した UnicodeDecodeError の対応方法について書きました。

背景(むかしばなし風)

昔々あるところにおじいさんとおばあさん、そしてPythonで書かれたスクリプトがおりました。スクリプトは全く同じものが複数のサーバーに配置され定期的に自動で実行されておりました。

ある日、サーバーのうちの1台が凶暴な妖怪の襲撃(ハード故障)を受け再起不能(リタイア)になってしまいました。おじいさんとおばあさんは新しいサーバーを構築して事態は収束したかにみえました。しかしPythonで書かれたスクリプトが正常に動いていないという新たな危機が訪れたのです...。

「自動実行が失敗しているのなら手動実行はどうじゃろう?」

おじいさんがスクリプトの手動実行を行ってみると、コンソールにこう表示されたのです。

UnicodeDecodeError と...。

エラー

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe3 in position xx: ordinal not in range(128) 

環境

OS: CentOS
DB: PostgreSQL
Language: Python 2.4

原因

Pythonのdefault encodingがasciiになっていたのが原因でした。
新設サーバーにインストールされたPythonのデフォルトエンコーディングはasciiでしたが、他の全てのサーバーではUTF-8が設定されていました。

問題のスクリプトはDBからデータを抜いて加工する処理を行っていたんですが、PythonとDBのデフォルトエンコーディングが違ったために発生してたのです。

環境構築時にPythonのデフォルトエンコーディングを変更していなかったのが原因のようです。

ちなみにPython3ではデフォルトエンコーディングがUTF-8になっているようなので、デフォルトエンコーディングを変更していなければ今回のような現象は起こりにくいと思います。

確認と対策

デフォルトエンコーディングの確認

Pythonのデフォルトエンコーディングを確認するために、コマンドラインでPythonを起動し、sysパッケージをインポートしてgetdefaultencodingメソッドを実行します。

$ python
import sys

sys.getdefaultencoding()
ascii

実行した結果、現在のデフォルトエンコーディングは ascii ということがわかりました。

デフォルトエンコーディングの変更

Python 2.x の場合は下記ファイルを修正。
もしもファイルが存在しない場合は新規作成してください。

/usr/lib/python2.x/site-packages/sitecustomize.py

sitecustomize.py に下記を記述してデフォルトエンコーディングをUTF-8に変更します。

import sys
sys.setdefaultencoding("utf-8")

デフォルトエンコーディングが変更されたか確認

デフォルトエンコーディングがUTF-8に変更されたかを確認します。先ほどデフォルトエンコーディングを確認したのと同じ方法を実行します。

$ python
import sys

sys.getdefaultencoding()
'utf-8'

デフォルトエンコーディングがUTF-8に変更されていることが確認できました。

スクリプトの動作確認

デフォルトエンコーディングをUTF-8に変更した後、問題のスクリプトを実行したところ正常に処理が完了しました。これで一安心。

参考サイト

今回のエラー対応時に参考になった記事です。

qiita.com

shu223.hatenablog.com

qiita.com

読者さん募集中

記事が気に入ったら読者登録をお願いします!