Pythonで日本語のエンコードエラーが発生したときの対応策

Pythonで日本語を使っていたら、下記のような日本語の文字コードエラーが発生しました。

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-7: ordinal not in range(128)

解決策をまとめます。

原因

正確に理解しているかわからないのですが、一応簡単に調べました。

Python3では、デフォルトで ANSI_X3.4-1968 というエンコード方式が標準入出力で使われているようです。

>>> import sys, io
>>> sys.stdout
<_io.TextIOWrapper name='<stdout>' mode='w' encoding='ANSI_X3.4-1968'>

これはASCII型に変換してくれるものですが、

  1. 日本語は非ASCII文字
  2. 日本語の結合をしたりするときにデコードが必要
  3. しかしPythonの文字列は自身のエンコードに関する情報を持っていない
  4. 日本語を無理やりASCII型でデコードしようとする

という感じでエラーが発生するようです。つまり、エンコード方式 にutf-8 を指定すれば良い。以下、対応策です。

対応策1…ファイルの冒頭でエンコーディング方式を指定

下記の行をファイルの冒頭に追記します。

import io,sys
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')

とりあえずこれを記述しておけば安心、という考えはバグの温床になりやすいので危険ですが、おそらくこれが一番簡単な方法なので、日本語を扱うときはこれを入れておくといいと思います。

対応策2…実行時にエンコーディング方式を指定

インタプリタでPythonのコードを実行する場合限定ですが、下記のように PYTHONIOENCODING という環境変数を指定することで、標準入出力のエンコーディングを上書きできます。

PYTHONIOENCODING=utf-8 python3 hogehoge.py

対応策3…環境変数を設定

毎回対応策2のように指定するぐらいなら、最初から設定しておけば楽チンです。

export PYTHONIOENCODING=utf-8

↑これを~/.bash_profileに追記します。dockerの場合はdockerfileに ENV PYTHONIOENCODING utf-8 を追記すればOKです。

まとめ

近年は自然言語処理などで日本語を扱うケースが増えてきているのかなと思いますが、日本語周りのエラーには悩まされそうです。