动态导入模块并实例化类在Python中

3 投票
1 回答
682 浏览
提问于 2025-04-17 00:15

我的问题和这个问题有点相似,但我想更进一步。

我正在解析一个配置文件,这个文件通过名字调用了一些动作(带参数)。比如:

"on_click": "action1", "args": {"rate": 1.5} 

这些动作是Python类,都是从一个基础的Action类继承而来的,可以接受命名参数。它们存放在项目的一个名为“actions”的子目录里,文件名都以a_开头。我希望能够通过简单地放一个新文件到这个目录里来添加新的动作,而不需要修改其他任何文件。项目的结构大致是这样的:

myapp/
    actions/
        __init__.py
        baseaction.py
        a_pretty.py
        a_ugly.py
        ...
    run.py

所有的动作类都提供了一个PerformAction()方法和一个GetName()方法,配置文件就是通过这个方法来引用的。在这个例子中,a_pretty.py定义了一个叫PrettyPrinter的类。调用PrettyPrinterGetName()方法会返回“action1”。

我想把PrettyPrinter类添加到一个字典里,用“action1”作为键,这样我就可以像下面这样创建它的新实例:

args = {'rate': the_rate}
instantiated_action = actions['action1'](**args)
instantiated_action.PerformAction()

目前,我有以下内容:

actions = [os.path.splitext(f)[0] for f in os.listdir("actions")
           if f.startswith("a_") and f.endswith(".py")]

for a in actions:

    try:
        module = __import__("actions.%s" % a, globals(), locals(), fromlist=["*"])
        # What goes here?
    except ImportError:
        pass

这段代码正在导入动作文件,如果我打印dir(module),我能看到类名;我只是还不知道接下来该怎么做(或者说这种方法是否正确...)。

1 个回答

2

如果你在你的 module 里所有的东西都是你需要创建实例的类,可以试试下面的做法:

对于每一个动作(actions)来说:

try:
    module = __import__("actions.%s" % a, globals(), locals(), fromlist=["*"])
    # What goes here?
    # let's try to grab and instanciate objects
    for item_name in dir(module):
        try:
           new_action = getattr(module, item_name)()
           # here we have a new_action that is the instanciated class, do what you want with ;)
        except:
           pass

except ImportError:
    pass

撰写回答