动态导入脚本列表 - Python

Importing a List of Scripts Dynamically - Python

假设我有 N python 个文件(每个文件都有一个 main 函数),文件结构如下:

tools \
|_ tool_1.py
|_ tool_2.py
...
|_ tool_N.py

此外,我有这样的数据结构:

files = [
    {"path":"tools/tool_1.py", "alias" : "tools__tool_1"}
    {"path":"tools/tool_2.py", "alias" : "tools__tool_2"}
    ...
    {"path":"tools/tool_N.py", "alias" : "tools__tool_N"}
]

如何将这些文件动态导入到单个 python 文件中?工具的数量会随着时间的推移而增加,手动为每个工具添加一行是不可行的。

那么我该如何转换:

from tools.tool_1 import main as tools__tool_1
from tools.tool_2 import main as tools__tool_2
...
from tools.tool_N import main as tools__tool_N

到这个?

for file in files:
    from file["path"] import main as file["alias"]

您需要调用exec()函数。请参阅下面的示例:

exec('from datetime import datetime')
print(datetime.now())

所以你的情况是:

for file in files:
    exec(f'from {file["path"]} import main as {file["alias"]}')

好的,首先是几个免责声明:(1) 动态导入模块可能是也可能不是您真正需要的。我自己这样做了,但在我的例子中,我有一个包含大约 100 个不同模型的库,以及一个通用驱动程序,该驱动程序根据我提供的命令行选项动态加载其中一个模型。要点是我一次不需要加载多个模块,因此动态加载一个模块是有意义的。

并且 (2) 我远不是导入模块和包的专家,但我通常能够让它做我想做的事。

话虽如此,如果您认为动态导入模块是您想要的,那么这应该适合您。请注意,我试图为您创建一个完整的示例:

import importlib

files = [
    {"path" : "tools.tool_1", "name" : "tools__tool_1"},
    {"path" : "tools.tool_2", "name" : "tools__tool_2"},
    {"path" : "tools.tool_3", "name" : "tools__tool_3"}
]

module_dict = {}
main_dict = {}

for file_desc in files:
    path = file_desc["path"]
    name = file_desc["name"]

    module = importlib.import_module(path)

    module_dict[name] = module
    main_dict[name] = module.main

main_dict["tools__tool_1"]()

在此示例中,三个模块都位于目录 tools 中。这些模块是 tool_1tool_2tool_3。它们以 tools__tool_1 等名称导入并存储在字典中。注意:您可以简单地使用 tool_1 等来表示这些名称,除非您需要使用 tools__ 来限定它们因为您想将其他目录中的模块加载到相同的词典中。

请注意,这些导入中的 none 对您的全局命名空间有任何影响。模块作为对象导入,它们(或它们的 main 函数)仅存储在字典中。

关于你需要什么,我不完全确定你想要什么,所以我创建了两个词典。第一个是 module_dict,它导入整个模块。第二个是 main_dict,它只包含来自每个导入模块的 main 函数,如原始 post 中所述。 请注意,每个模块只导入一次。如果您只需要其中一本词典,只需删除不需要的词典即可。

无论如何,假设您想从 tools.tool_1 调用 main。您可以从 main_dict 执行此操作,如下所示:

    main_dict["tools__tool_1"]()

如果您想从 module_dict 调用它或任何其他函数,您可以这样做:

    module_dict["tools__tool_1"].main()

您基本上可以从 module_dict 访问模块中的所有内容,但如果您只想访问 main,那么您可以只使用 main_dict.

同样,这里可能比您需要的更多,但我不完全确定您打算如何使用它。如果您只需要其中一本词典,只需去掉另一本即可。