Pythonで動的にインスタンスを作成したり、メソッドを取得して呼び出したり・・・といった、リフレクションの方法についてまとめ。
動的なインスタンス生成
Pythonで文字列などから動的にインスタンスを作成したい際は以下のようにする。
※例として、例外クラス(Exception)のインスタンスを作成してみる。
mod = __import__("exceptions",fromlist=["Exception"])
class_def = getattr(mod,"Exception")
obj = class_def("message") # obj = Exception('message',)
先頭の__import__
は、インポート宣言に該当する(上記の例ではfrom exceptions import Exception
を行ったのと同じ意味になる。なお、exceptionsは明示的に読み込む必要はない。あくまで例として挙げている)。
このモジュールからgetattr
により該当クラスのクラス定義を取得し、最後はそれを利用してオブジェクトを作成する。
<参考>
How to dynamically load a Python class
メソッド定義の取得
メソッドも含めたクラスなどの定義の取得にはinspectを利用する。
inspect.getmembers
によって定義を取得し、getattr
でオブジェクトからの定義を取得、それを実行するという流れになる。
もちろん、メソッド名にあらかじめあたりがついていれば直接getattr
を呼び出してよい。
upper_method = filter(lambda f: f[0] == "upper", inspect.getmembers("String",inspect.isroutine))[0]
invoker = getattr("abc",upper_method[0])
invoker() # 'ABC'
デコレーターがついているものだけ取りたいなー、というのは当然の希望だが、現在のところ非常に泥臭い方法しかないようだ(具体的には、ソースコードを読み込み@始まりのものを探す感じになる)。
プロパティの取得
Publicなプロパティ(メンバ変数)を全部取得したい、という場合は以下のようにする。
attributes = inspect.getmembers(self, lambda a: not(inspect.isroutine(a)))
filter(lambda a: not(a[0].startswith("__")), attributes)
isroutine
に該当しないもの=メンバ変数を抽出し、その名前の先頭が__
で始まらないもの、を抽出している。
取得したプロパティから値を取得するには、メソッド同様getattr
を利用する。