概要
Pythonでモジュール、関数、クラスを名称の文字列から取得する。
バージョン情報
- Python 3.7.4
事前準備
下記のようなコードを書いて foo.py というファイル名で保存する。
class Foo: def hello(self): print('hello')
サンプルコードではこのモジュールを文字列でimportする。
evalとexecですべては解決する
書き捨てるだけのコードの時は面倒なのでevalとexecで済ませる。
# モジュールのimport exec('import foo') foo.Foo().hello() #=> hello # クラスの初期化 foo = eval('foo.Foo()') foo.hello() #=> hello # メソッドの呼び出し eval('foo.hello()') #=> hello
importlib.import_module
すぐには捨てないコードではお行儀的にはexecよりはマシなimportlibを使ってモジュールやクラスをimportする。
import importlib # fooモジュールをimport foo = importlib.import_module('foo') foo.Foo().hello() #=> hello
余談
importlibにあるreloadを使うと一度importしたコードを再度読み直せる。
# fooの読み直し
importlib.reload(foo)
Jupyter等でimport先のコードを修正した時に、autoreloadは使わずにこっちで明示的にやりたいケースがたまにあるようなないような。
getattrでクラスやメソッドの取得
getattrでモジュールからクラスを取得したりメソッドを取得できる。
import importlib foo = importlib.import_module('foo') # モジュールから文字列でクラスを取得 Foo = getattr(foo, 'Foo') Foo().hello() #=> hello # クラスからメソッドを呼び出す foo_inst = Foo() hello = getattr(foo_inst, 'hello') hello() #=> hello
モジュールの存在チェック
importlib.util.find_specでモジュールが存在をチェックできる。
import importlib # fooモジュールが存在するかチェック if importlib.util.find_spec('foo'): foo = importlib.import_module('foo') else: # do something
try importするより良さげ。
読み込み可能なモジュールの一覧を取得する
pkgutilを使うと読み込み可能なモジュールを一覧で取得できる。
import pkgutil for info in pkgutil.iter_modules(): print(info)
指定パッケージ配下のモジュールのみ一覧で出すことも可能。
試しにbarパッケージを下記のように作成する。
$ mkdir bar $ touch bar/__init__.py $ echo 'hello = lambda : print("hello bar1")' > bar/bar1.py $ echo 'hello = lambda : print("hello bar2")' > bar/bar2.py # パス構成確認 $ tree . . ├── bar │ ├── __init__.py │ ├── bar1.py │ └── bar2.py └── foo.py
barパッケージのモジュールを表示する。
for x in pkgutil.iter_modules(['bar']): print(x) #=> ModuleInfo(module_finder=FileFinder('bar'), name='bar1', ispkg=False) #=> ModuleInfo(module_finder=FileFinder('bar'), name='bar2', ispkg=False)
これで文字列で指定されたパッケージ配下のモジュールをまとめてimportできる。
package_name = 'bar' bar = dict([ (info.name, importlib.import_module('.' + info.name, package=package_name)) for info in pkgutil.iter_modules([package_name]) ]) bar['bar1'].hello() #=> hello bar1
こんなことをするシチュエーションがあるのかどうかは置いておいて。
変数がモジュールなのかクラスなのか確認する
getattrで操作していると取得したものがモジュールなのかクラスなのか関数なのか不明瞭になるので、insepectを使って確認する。
import importlib import inspect # モジュールチェック foo = importlib.import_module('foo') inspect.ismodule(foo) #=> True inspect.isclass(foo) #=> False # クラスチェック Foo = getattr(foo, 'Foo') inspect.isclass(Foo) #=> True # メソッドチェック foo_inst = Foo() inspect.ismethod(getattr(foo_inst, 'hello')) #=> True inspect.isfunction(getattr(foo_inst, 'hello')) #=> False # ファンクションチェック def hoge(): pass inspect.isfunction(hoge) #=> True inspect.ismethod(hoge) #=> False
他にもisgeneratorとかisbuiltinとかいろいろなタイプがチェックできる。
https://docs.python.org/3/library/inspect.html
Pythonで「どれが関数でどれがメソッドかわかりません」といった初期にありがちな質問に対する回答用としても使える。
改定履歴
Author: Masato Watanabe, Date: 2020-05-05, 記事投稿