如何导入所有子模块?

2024-04-26 18:43:13 发布

您现在位置:Python中文网/ 问答频道 /正文

我的目录结构如下:

| main.py
| scripts
|--| __init__.py
   | script1.py
   | script2.py
   | script3.py

main.py导入模块scripts。我尝试将pkgutils.walk_packages__all__结合使用,但是使用它,我只能使用from scripts import *导入main下的所有子模块。我想把它们都放在scripts下面。导入scripts的所有子模块以便我可以从main访问scripts.script1的最干净的方法是什么?

编辑:很抱歉我有点含糊。我希望在运行时导入子模块,而不在__init__.py中显式指定它们。我可以使用pkgutils.walk_packages来获取子模块名称(除非有人知道更好的方法),但是我不确定使用这些名称的最干净的方法(或者walk_packages返回的ImpImporters?)以导入它们。


Tags: 模块方法py目录名称initmainpackages
3条回答

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

(顶层包目录中__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

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

也许有更好的办法,但无论如何,这是我能做的最好的办法。

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

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

import script1
import script2
import script3
__all__ = ['script1', 'script2', 'script3']

你甚至可以不定义__all__,但是如果你定义了它(pydoc,如果没有其他东西的话),即使它只是你导入的内容的列表,它的工作也会更干净。

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

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__)
    }

用法:

__all__ = import_submodules(__name__).keys()

这是基于the answer that kolypto provided,但他的答案不执行包的递归导入,而这是基于the answer that kolypto provided。尽管主问题不需要递归导入,但我相信递归导入适用于许多类似的情况,并且非常有用。一、 首先,在搜索主题时发现了这个问题。

这是执行子包模块导入的一种好的、干净的方法,而且应该是可移植的,并且它使用了Python2.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

用法:

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

# Alternatively, from scripts.__init__.py
import_submodules(__name__)

相关问题 更多 >