UE4 の Python で自作モジュールを使う方法

 1つの Python スクリプトに全部書くのはもう嫌だの巻

Python を書くとき、1 つの Python スクリプトに全部書いてしまうと身通しが悪くなるので、 普通はこちらのようにモジュールを分けて書いていくと思います。

# libs/foo.py
class Foo:
  def print(self):
    print("Foo!")

# main.py
from libs.foo import Foo

f = Foo()
f.print()

コマンドラインから実行すると、こんな感じで実行されます。

D:\Path\To> python main.py
Foo!
D:\Path\To>

ところがこれを UE4 の Python プラグインで実行すると、なぜかエラーになることがあります。 (正確には、Python スクリプトを /Content/Python の直下に置いている時は動作しますが、それ以外のフォルダに置いている時にエラーになります)

LogPython: Error: Traceback (most recent call last):
LogPython: Error:   File "D:/Path/To/main.py", line 1, in <module>
LogPython: Error:     from libs.foo import Foo
LogPython: Error: ModuleNotFoundError: No module named 'libs.foo'

なんでやねん! UE4 で Python のツールを書き出した時はこの問題が解決できず、あきらめて全機能を 1 つの Python スクリプトの中に書いていました…。

だいぶ後になってわかったのですが、以下のように書けば動きます。 インクルードパスに、実行対象の Python スクリプトが置かれているフォルダを追加します。

# main.py
import sys
import os
sys.path.append(os.path.dirname(__file__)) # この行を追加
from libs.foo import Foo

f = Foo()
f.print()

めでたしめでたし…とは行きません。Python を書くのに VSCode をお使いの方には凄まじいトラップがあります。

VSCodeがお勧めする強烈なトラップ

フォーマッタ autopep8 を入れますか?とお勧めしてくるので言われるがままにインストールしてしまうと、

# main.py
from libs.foo import Foo
import sys
import os
sys.path.append(os.path.dirname(__file__))
  :

こんな感じで勝手に順序を入れ替えてしまい、動かなくなります。 (autopep8 はダメですが、ついでにお勧めされる black, yapf では問題ありません)

ということで、無事 UE4 の Python でもモジュールが使えることがわかりました。

また、モジュール構成を変えた時はソースに問題がなくても No module named '...' の エラーが出ることがあります。 逆に、明らかにモジュールが解決できない状況でもエラーが出ないことがあり、頭を悩ませることがあります。 そういうときは、UE4 のエディタをいったん終了し、再実行しましょう。 ちゃんと追い切れてないんですが、どうも前回のモジュール解決情報が残っているようです…。

上記は UE4.26(Python3.7)で確認しました。UE4.25 以前(Python2.7)では、 上記構成に加えて libs/__init__.py というファイル名で空ファイルを作っておく必要があります。

文責:ともたこ/Tomotaka Ogino Twitter/github/Qiita