如何导入所有子模块?

lin*_*r03 36 python import module

我有一个目录结构如下:

| main.py
| scripts
|--| __init__.py
   | script1.py
   | script2.py
   | script3.py
Run Code Online (Sandbox Code Playgroud)

main.py,scripts导入模块.我尝试pkgutils.walk_packages结合使用__all__,但使用它,我只能在main使用时直接导入所有子模块from scripts import *.我想让他们全都失望scripts.什么是进口的所有子模块的干净的方式scripts,这样我可以访问scripts.script1main

编辑:对不起,我有点模糊.我想在运行时导入子模块而不明确指定它们__init__.py.我可以pkgutils.walk_packages用来获取子模块名称(除非有人知道更好的方法),但我不确定使用这些名称(或者可能walk_packages返回的ImpImporters ?)的最简洁方法来导入它们.

Joe*_*ton 34

编辑:这是在运行时以递归方式导入所有内容的一种方法...

(__init__.py顶级包目录中的内容)

import pkgutil

__all__ = []
for loader, module_name, is_pkg in  pkgutil.walk_packages(__path__):
    __all__.append(module_name)
    _module = loader.find_module(module_name).load_module(module_name)
    globals()[module_name] = _module
Run Code Online (Sandbox Code Playgroud)

我没有__import__(__path__+'.'+module_name)在这里使用,因为使用它正确地递归导入包很困难.但是,如果您没有嵌套的子包,并且想要避免使用globals()[module_name]它,那么这是一种方法.

可能有更好的方法,但无论如何,这是我能做的最好的方法.

原始答案(对于上下文,忽略其他方面.我最初误解了这个问题):

你的scripts/__init__.py样子是什么样的?它应该是这样的:

import script1
import script2
import script3
__all__ = ['script1', 'script2', 'script3']
Run Code Online (Sandbox Code Playgroud)

你甚至可以不进行定义__all__,但是如果你定义的话,事情(pydoc,如果没有别的话)会更干净地工作,即使它只是你导入的列表.

  • 使用exec()是过度的 - 您可以将加载的模块戳入globals()并解决问题. (3认同)
  • 这只是我还是这不适用于相对进口?如果我有带有“from .. import script2”行的“script1/file1.py”,我会收到一个错误“ValueError:试图在顶级包之外进行相对导入”。 (2认同)
  • 如果您需要相对导入才能工作:添加 `import importlib` 并将行加载模块替换为 `_module = importlib.import_module('{}.{}'.format(__name__, module_name))`。 (2认同)

Mr.*_*. B 29

这是基于kolypto提供的答案,但他的答案不执行包的递归导入,而这样做.虽然主要问题不需要,但我相信递归导入适用,并且在许多类似情况下非常有用.例如,我在搜索主题时发现了这个问题.

这是执行子包模块导入的一种很好,干净的方法,也应该是可移植的,它使用python 2.7+/3.x的标准库.

import importlib
import pkgutil


def import_submodules(package, recursive=True):
    """ Import all submodules of a module, recursively, including subpackages

    :param package: package (name or actual module)
    :type package: str | module
    :rtype: dict[str, types.ModuleType]
    """
    if isinstance(package, str):
        package = importlib.import_module(package)
    results = {}
    for loader, name, is_pkg in pkgutil.walk_packages(package.__path__):
        full_name = package.__name__ + '.' + name
        results[full_name] = importlib.import_module(full_name)
        if recursive and is_pkg:
            results.update(import_submodules(full_name))
    return results
Run Code Online (Sandbox Code Playgroud)

用法:

# from main.py, as per the OP's project structure
import scripts
import_submodules(scripts)

# Alternatively, from scripts.__init__.py
import_submodules(__name__)
Run Code Online (Sandbox Code Playgroud)

  • 这太棒了,正是我所需要的!谢谢! (2认同)

kol*_*pto 13

简单地工作,并允许相对导入包内:

def import_submodules(package_name):
    """ Import all submodules of a module, recursively

    :param package_name: Package name
    :type package_name: str
    :rtype: dict[types.ModuleType]
    """
    package = sys.modules[package_name]
    return {
        name: importlib.import_module(package_name + '.' + name)
        for loader, name, is_pkg in pkgutil.walk_packages(package.__path__)
    }
Run Code Online (Sandbox Code Playgroud)

用法:

__all__ = import_submodules(__name__).keys()
Run Code Online (Sandbox Code Playgroud)