概要
競馬予測AIを作るアプリケーションをPythonで作ろうとしていたらJupyterではうまくいっていたのに素のPythonに移したら文字化けが発生した
pyenvのshimsというものを通したPythonにアクセスしていたのが問題だった。
直接Pythonの本体にアクセスしたら解決した。
事象
もともと競馬予測AIを作る案件に参画していたところ、Jupyterでうまくいっていたのに、実際にバッチ化するにあたり素のPythonに変えたら日本語が無限に文字化けする事象に遭遇した。
構築はpywin32を使うためにpyenvでpython3.11.7-32bitを導入
そのままpyenv global 3.11.7
を設定した。
大まかにいうと下記のコードでJupyterではうまく動いていたので、素のPythonで写したところ、文字化けが発生するようになった。
想定される正常系は下記のように日本語が正常にパースするものだが、ここが@@@@のようになっていた。
似たような事象: https://note.com/mare_ism/n/n8840715b32a4
{'record_type_id': 'RA', 'data_category': '7', 'data_creation_date': '20190107', 'year': '2019', 'month_day': '0105', 'race_course_code': '06', 'round_number': '01', 'day_number': '01', 'race_number': '09', 'day_of_week_code': '1', 'special_race_number': '0000', 'race_name_main': '招福ステークス', 'race_name_sub': '', 'race_name_bracket': '', 'race_name_main_english': 'SHOFUKU STAKES', 'race_name_sub_english': '', 'race_name_bracket_english': '', 'race_name_abbr_10': '招福ステークス', 'race_name_abbr_6': '招福S', 'race_name_abbr_3': '招福S', 'special_race_round_indication': '0', 'special_race_round': '000', 'grade_code': 'E', 'prev_grade_code': ' ', 'race_type_code': '14', 'race_symbol_code': 'A03', 'weight_type_code': '1', 'race_condition_code_2yo': '000', 'race_condition_code_3yo': '000', 'race_condition_code_4yo': '016', 'race_condition_code_5up': '016', 'race_condition_code_youngest': '016', 'race_condition_name': '', 'distance': '1800', 'prev_distance': '0000', 'track_code': '24', 'prev_track_code': '00', 'course_section': '', 'prev_course_section': ' ', 'first_prize_money': [18200, 595, 59, 5000002, 7000000, 1820000, 0], 'additional_prize_money': [3, 36000, 72], 'start_time': '1425', 'prev_start_time': '0000', 'num_registered': '15', 'num_started': '15', 'num_finished': '15', 'weather_code': '1', 'turf_condition_code': '0', 'dirt_condition_code': '1', 'lap_times': [127, 113, 126, 129, 127, 125, 121, 122, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'barrier_mile_time': '0000'}
解決
Jupyterで動くということはkernelに差異があると調べていたところ、Jupyterと素のPythonではアクセスしているところが異なることを発見した。
Jupyterのカーネルは~\.pyenv\pyenv-win\versions\3.11.7-win32\python.exe
に対して、whereで確認したPythonは~\.pyenv\pyenv-win\shims\python3
を指していた。
説明
ChatGPT君に聞いたところ下記のような回答が返ってきた。
裏付けのために調べたところどうやらpyenvはshimsコマンドというものでpyenvを呼び出すような動作をしているらしく、ここのshimsコマンドもまたエンコーディング処理をしているらしい。面倒。
.pyenvを使用している環境で、特定のPythonインタプリタを実行したときに日本語が文字化けするのは、shimsを介して実行されるPythonと直接実行されるPythonの間で環境やエンコーディング設定が異なるためと考えられます。.pyenvのshimsディレクトリにあるpython3やpython3.batは、実際のPythonインタプリタへのプロキシとして機能します。これらのファイルを介してPythonを実行すると、追加の環境設定やエンコーディング処理が行われることがあります。
shimsによる実行と直接実行の違い環境変数:
shimsを使用すると、pyenvはPythonインタプリタを起動する前に特定の環境変数を設定することがあります。これにより、エンコーディングやロケールに関連する環境変数が変更され、文字化けの原因となる可能性があります。エンコーディング設定:
shimsを介して起動されたPythonは、pyenvによって設定されたデフォルトのエンコーディングを使用する場合があります。これがシステムのデフォルトや直接起動したときのエンコーディングと異なると、文字化けが発生することがあります。Pythonの実行パス:
直接pyenv-win\versions...下のpython.exeを実行すると、そのPythonインタプリタはpyenvの追加のラッパーや環境設定なしで実行されます。これにより、システムのデフォルトのエンコーディングや設定が使用され、文字化けが発生しない場合があります。解決策
エンコーディングの明示的な指定:
Pythonスクリプト内でエンコーディングを明示的に指定することで、異なる環境で実行されても一貫した動作を期待できます。例えば、ファイルを開く際にencoding='utf-8'を指定します。環境変数の調整:
PYTHONIOENCODING環境変数をutf-8など適切な値に設定することで、Pythonが使用するデフォルトのエンコーディングを強制できます。pyenvの設定の見直し:
pyenvの設定を見直し、エンコーディングに影響を与える可能性のある設定がないか確認します。shimsと直接実行の違いを理解し、適切なエンコーディング設定や環境変数の調整を行うことで、Python環境間での文字化け問題を解決できるはずです。
結論
pyenvのshimsというものを通したPythonにアクセスしていたのが問題だった。
直接Pythonの本体にアクセスしたら解決した。
参考