指定したモジュール配下から、特定クラスのサブクラスを探す
- お題 : 「a.b モジュール配下にある a.Base のサブクラスのリストを表示したい」
Seasar や Spring のコンポーネントの自動登録みたいなイメージで。ふと思い立って python で書いてみました。
ファイルの構成は以下の通りで、該当の処理を x.py の中に書く事にします。
- __init__.py - x.py - a +- __init__.py +- b +- __init__.py +- c +- __init__.py
クラスは各々の __init__.py で以下のように定義してあるます。
- a.Base
- a.A (extends a.Base)
- a.Not
- a.b.B (extends a.Base)
- a.b.Not
- a.b.c.C (extends a.Base)
- a.b.c.Not
ここから、a.b 配下で a.Base のサブクラスの a.b.B と a.b.c.C を探すコードはこんな感じで。
# -*- coding: utf-8 -*- from types import ClassType import os def traversal(module_name,clazz): mod = __import__(module_name, {}, {}, ['']) for name in dir(mod): name_obj = mod.__dict__[name] if type(name_obj) in [ClassType,type]: if issubclass(name_obj,clazz) and name_obj != clazz : print name_obj # child moddir = os.path.dirname(mod.__file__) for child in os.listdir(moddir): p = os.path.join(moddir,child) if os.path.isdir(p) : traversal(".".join([module_name,child]),clazz) if __name__ == "__main__" : import a traversal("a.b",a.Base)
緩いコードとはいえ、こういうことするの楽ですね、特に変わったもの使わないですし。もっと簡単に書く方法ありそうですが。
余談ですが、GAE/P の webapp.template.register_template から呼ばれるdjango.template の中の get_library も似たような処理してました。register って、まま名前でアクセスしてますね。この辺り大胆だなぁ、とも感じます。
def get_library(module_name): lib = libraries.get(module_name, None) if not lib: try: mod = __import__(module_name, {}, {}, ['']) except ImportError, e: raise InvalidTemplateLibrary, "Could not load template library from %s, %s" % (module_name, e) try: lib = mod.register libraries[module_name] = lib except AttributeError: raise InvalidTemplateLibrary, "Template library %s does not have a variable named 'register'" % module_name return lib