任意のディレクトリ以下にあるサブクラスをすべて取得する
あるディレクトリ以下に存在する .py の中から、任意のクラスのサブクラスを
リストアップする関数を作ってみました。
私はこの関数を、自作エディタのプラグインの検索に使っています。
# -*- coding: utf-8 -*- import sys import os import inspect def get_subclass(dirPath, baseCls): ''' 指定されたディレクトリパス以下に存在するbaseClsのサブクラスのみを取得し、 リストで返す。 path: 処理対象ディレクトリ baseClass: 基底クラスオブジェクト RETURN: クラスのリスト。 ''' clsSet = set() for p in os.listdir(dirPath): itemPath = os.path.join(dirPath, p) if os.path.isfile(itemPath): fname, ext = os.path.splitext(p) if ext not in ['.py', '.pyc']: continue if fname == '__init__': continue # モジュール名を取得 modName = inspect.getmodulename(itemPath) if not modName: continue modDir = os.path.split(dirPath)[1] if not modDir: continue # モジュールをインポートする mod = __import__('.'.join([modDir, modName])) mod = getattr(mod, modName) # クラスの抽出 for name, cls in inspect.getmembers(mod, inspect.isclass): # 指定されたベースクラス自身、またはモジュール内でインポート # されているクラスの場合には無視。 if cls == baseCls or inspect.getmodule(cls) != mod: continue # ベースクラスのサブクラスでない場合には無視。 if not issubclass(cls, baseCls): continue clsSet.add(cls) del mod elif os.path.isdir(itemPath): for cls in get_subclass(itemPath, baseCls): clsSet.add(cls) else: pass return list(clsSet)
上記のソース中でのポイントとしては、以下の部分です。
# モジュールをインポートする mod = __import__('.'.join([modDir, modName])) mod = getattr(mod, modName)
こうすることで、異なるディレクトリ中に同じ名前の.pyファイルがあった場合でも
それらを別のモジュールとして扱うことができます。
逆にこうしないと、異なるディレクトリ中に同じ名前の.pyファイルがあった場合、
最初に見つかった.pyファイルしか処理されません。
もっといい方法があるかもしれませんけど。。