こんにちは。サービス部の武田です。
Pythonでは変数名などに付けられる名前として命名規約があります。モジュールやパッケージ名も同様です。ところで、一般的にモジュールはOSのファイル、パッケージはディレクトリがそれぞれ対応します。そのため、Pythonとしては不正な(命名規約から外れた)名前をファイルやディレクトリにつけることも可能です。
その場合、もちろん不正な名前なので別ファイルからimportができません。そのため、通常であればファイル名なりを変更するべきです。ですが、何らかの理由で今すぐ名前を変更できないが、importして使いたいというケースに出会うこともあるでしょう。今回はその方法を紹介します。再度言いますが、まずは名前変更を検討してください。
不正な名前の例
たとえばPythonの予約語はモジュール名として不正です。ここではlambda.py
というファイルを作成してみます。
$ tree
.
├── main.py
└── test
├── __init__.py
└── lambda.py
lambda.py
は関数を定義しているだけです。
test/lambda.py
def hello():
print("Hello World!")
このファイルを別ファイルからimportしてみます。
main.py
import test.lambda
test.lambda.hello()
実行しようとしてもできません。
File "/tmp/main.py", line 1
import test.lambda
^
SyntaxError: invalid syntax
import_moduleを使う方法
先ほど見たように、予約語などはinvalid syntax
となってimportできませんでした。そこで文字列として指定する方法に切り替えます。importlib.import_module
は引数としてimportしたいモジュールを指定し、動的にインポートするための関数です。
main.py
import importlib
mymod = importlib.import_module("test.lambda")
mymod.hello()
この方法であれば、問題なくimportして実行できます。
$ python3 main.py
Hello World!
SourceFileLoaderを使う方法
別の方法として、ロードしたいファイルを直接指定する方法もあります。同じように動的にインポートできますが、手順が先ほどより増えています。
main.py
from importlib import machinery, util
from pathlib import Path
mod_path = Path("test/lambda.py")
loader = machinery.SourceFileLoader(str(mod_path), str(mod_path))
spec = util.spec_from_file_location(str(mod_path), mod_path, loader=loader)
mymod = util.module_from_spec(spec)
spec.loader.exec_module(mymod)
mymod.hello()
この方法でも、問題なくimportして実行できます。
$ python3 main.py
Hello World!
まとめ
最初にも言いましたが、まずは不正な名前を付けないようにするのが先決です。それでも付けてしまい、かつ変えられない事情があり、何とかimportしたいんだ!という状況になってしまった時に、思い出してもらえればと思います。