文字列で指定しているモジュールを import する
前回のセッションバックエンドについて書いた。 Djangoのセッションバックエンドを調べる(file, db) - そのあれ
そのとき、 django の設定ファイルでは文字列でパスを指定している。ただ、文字列をパスで指定しているだけでどう読み込んでいるかまでよく知らなかった。
セッションバックエンドの指定では django/middleware.py at master · django/django · GitHub で使われている。
結論
__import__
をつかうか importlib.import_module
をつかう。
- Pythonでスクリプトを動的にimportする - Qiita
- 31.5. importlib – The implementation of import — Python 3.4.3 ドキュメント
あまり詳しく調べてないけど、特に理由がなければ importlib.import_module
のほうが標準ライブラリなのでいいんじゃないかなという感じがする。実際、 import_module
関数の中ではキャッシュやロックの管理のようななにかが書かれている。
検証
リポジトリはこちら altnight/djsession at importlib · GitHub
こういう構成になっている。
$ cat app_a/__init__.py print('init %s' % __file__) $ cat hello.py print('hello %s' % __file__)
__init__.py
と hello.py
という import すると自身のファイルパスを表示するだけのモジュール。
$ tree app_a app_a ├── __init__.py ├── hello.py └── level1 ├── __init__.py ├── hello.py └── level2 ├── __init__.py └── hello.py 2 directories, 6 files
ためしにつかう main.py
はこういう内容。
import_module
でモジュール指定__import__
でモジュール指定import_module
でパッケージ指定__import__
でパッケージ指定
from importlib import import_module import_module('hello') import_module('app_a.hello') import_module('app_a.level1.hello') import_module('app_a.level1.level2.hello') #__import__('hello') #__import__('app_a.hello') #__import__('app_a.level1.hello') #__import__('app_a.level1.level2.hello') #import_module('app_a') #import_module('app_a.level1') #import_module('app_a.level1.level2') #__import__('app_a') #__import__('app_a.level1') #__import__('app_a.level1.level2')
結果
$ python main.py hello /Users/altnight/u/src/djsession/djsession/hello.py init /Users/altnight/u/src/djsession/djsession/app_a/__init__.py hello /Users/altnight/u/src/djsession/djsession/app_a/hello.py init /Users/altnight/u/src/djsession/djsession/app_a/level1/__init__.py hello /Users/altnight/u/src/djsession/djsession/app_a/level1/hello.py init /Users/altnight/u/src/djsession/djsession/app_a/level1/level2/__init__.py hello /Users/altnight/u/src/djsession/djsession/app_a/level1/level2/hello.py
ちなみにパッケージじゃなくても(=ディレクトリに init.py がなくても) import できる。