在不修改 sys.path 的情况下在外部目录中查找 类

Finding classes in an external directory without modifying sys.path

我有一个函数,它接受一个包含一些 python 文件的外部路径,并发现这些文件中存在的任何 classes。它 returns class 名称和 class 本身的映射,以便我可以根据需要创建一个对象。下面的代码按照我的预期工作,但我试图在不附加 sys.path.

的情况下执行此操作
def find_plugins(path):
    sys.path.append(path)   
    plugin_map = {}
    current_module_name = os.path.splitext(os.path.basename(path))[0]
    for file in glob.glob(path + '/*.py'):
        name = os.path.splitext(os.path.basename(file))[0]

        if name.startswith('__'):
            continue

        module = importlib.import_module(name, package=current_module_name)
        for member in dir(module):
            plugin_class = getattr(module, member)
            if plugin_class and inspect.isclass(plugin_class):
                plugin_map[member] = plugin_class
    return plugin_map

如果删除 sys.path 行,我会得到以下堆栈跟踪:

ModuleNotFoundError: No module named 'plugin'

其中 'plugin' 是提供给函数的路径中的 plugin.py 文件。甚至可以在不附加 sys.path 的情况下执行此操作吗?

您可以使用 accepted answer to the question
How to import a module given the full path 中显示的技术来完成,它不需要操作 sys.path

import importlib.util
import inspect
from pathlib import Path


def find_plugins(path):
    plugins = {}
    for module_path in Path(path).glob('*.py'):
        module_name = module_path.stem
        if not module_name.startswith('__'):
            # Load module.
            spec = importlib.util.spec_from_file_location(module_name, module_path)
            module = importlib.util.module_from_spec(spec)
            spec.loader.exec_module(module)  # Execute module in its own namespace.
            # Extract classes defined in module.
            for member in dir(module):
                plugin_class = getattr(module, member)
                if plugin_class and inspect.isclass(plugin_class):
                    plugins[member] = plugin_class

    return plugins


if __name__ == '__main__':
    from pprint import pprint

    plugins_folder = '/path/to/plugins'
    plugins = find_plugins(plugins_folder)

    pprint(plugins)