LoginSignup
51
48

More than 5 years have passed since last update.

モジュールの動的読み込み

Last updated at Posted at 2015-07-25

なんとなくWebで見つけた今までの方法(imp.load_module)はdeprecatedだったため、Python 3.4におけるモジュールの動的読み込み処理を調べてみた。

ファイル構成

top
  |- main.py
  |- foo
          |- __init__.py
          |- some.py
          |- sample.py
  |- bar
          |- __init__.py
          |- some.py

古い方法

imp.load_module を使う方法で、find_module() の結果を使用してload_module() でモジュールを読み込む。
このとき、モジュール名(属性 __name__ )は load_module の第一引数nameが設定される。
Pythonではモジュールを sys.modules に登録するが、後勝ちになって先に読み込んだモジュールは上書きされてしまうことに注意する。
このため、fooとbarの両方のsome.pyを同じ名前someで読み込むと、意図しないものになることがある。

import sys
import imp

def load(dir_name:str, symbol:str): # -> module
    (file, path, description) = imp.find_module(dir_name + '/' + symbol)
    return imp.load_module(symbol, file, path, description)

m = load('foo', 'some')
m.__name__ # -> 'some'
sys.modules['some'] # -> 'module'

n = load('bar', 'some')
m == n # -> True

新しい方法

imp の置き換えとして importlib を使う。
importlib.import_module で、相対パスそのままでモジュールを読み込む。

import importlib

m = importlib.import_module('foo.some') # -> 'module'
m.__name__ # -> 'foo.some'

n = importlib.import_module('bar.some') # -> 'module'
n.__name__ # -> 'bar.some'

モジュール名を変えたいとき

古い方法と同様に、相対パス名を無視してモジュール名を自在に設定できるだろうか?
公式ドキュメントで imp.load_module の置き換えとして紹介されているものに次がある。
SourceFileLoader() を使い、その第一引数にモジュール名を設定することができる。
モジュール名(ここではsome)は、やはり後勝ちとなる。別の名前を設定することができるので、必要に応じて設定する。

import importlib.machinery as imm
datum = imm.SourceFileLoader('some', 'foo/some.py').load_module()

モジュール名の影響

foo/sample.pyでsome.pyを使用するとき、かつ動的に読み込む際の影響。
sampleを動的に読み込む場合、importで指定するモジュール名は sys.modules への登録名となる。上でモジュール名を変えていたときは、ここのimportにも影響する。

import some   # or
import foo.some

まとめ

  • Python 3.4 におけるモジュールの動的読み込みを調べた
  • importlibないしその配下のモジュールを使用する
  • モジュール名の扱いに注意する
51
48
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
51
48