Pythonで動的にクラスをロードしたい件

app-engine-patchを使っていて、settings.pyに記述されているAUTH_USER_MODELクラスを動的にロードしたかったんですが、簡単に方法が解らなかったのでメモしておきます。要はクラス名が文字列で与えられている場合に、そのクラスにアクセスしたいという話です。

まず対象のクラスが既にimportされている状態であれば、組込み関数のglobalsを使えます。

class Hoge:
  pass
hoge_klass    = globals()['Hoge']
hoge_instance = hoge_klass()

しかし設定ファイルに書かれているクラスをロードするケースでは、対象クラスがimportされていない事も多いと思います。そこでクラスを動的にimportしたい訳ですが、僕が調べた限りでは、一旦クラスが属しているモジュールをimportし、そのモジュールからクラスを得るという手順が必要なようです。モジュールからクラスの取得にはgetattrを使います。コードとしては以下になります。

path_to_class = 'package.module.class_name'  # このクラスをロードしたい
target = path_to_class.split('.')
(package, module, cls_name)  = (target[0], '.'.join(target[:-1]), target[-1])

# __import__したモジュールからcls_nameクラスを取得
klass = getattr(__import__(module, fromlist=[package]), cls_name)  
klass_instance = klass()

クラスへの絶対パスからpackage名, module名, class名に分解して, __import__, getattrで使用しています。ここで注意したいのは__import__のfromlistにパッケージを指定する必要がある事です。fromlistが指定されないと、例えばpackage.moduleを指定しても期待したmoduleではなく、packageモジュールが返却されます。リファレンスに書かれているのですが、読み落としてしまいハマりました。

ということで一応上記の方法でパスが与えられたクラスをロードできますが、モジュールを介しているのが気持ち悪いです。やりたい事は from package.module import class_name なので、__import__とかで一発で出来そうですが、探せませんでした。ご存知であれば教えて下さいませ。

Leave a Reply

Your email address will not be published. Required fields are marked *