有人能为我提供一个导入整个模块目录的好方法吗? 我有一个这样的结构:

/Foo
    bar.py
    spam.py
    eggs.py

我尝试通过添加__init__.py并从Foo import *将其转换为一个包,但它没有按我希望的方式工作。


当前回答

只需通过importlib导入它们,并在包的__init__.py中递归地将它们添加到__all__(添加操作是可选的)。

/Foo
    bar.py
    spam.py
    eggs.py
    __init__.py

# __init__.py
import os
import importlib
pyfile_extes = ['py', ]
__all__ = [importlib.import_module('.%s' % filename, __package__) for filename in [os.path.splitext(i)[0] for i in os.listdir(os.path.dirname(__file__)) if os.path.splitext(i)[1] in pyfile_extes] if not filename.startswith('__')]
del os, importlib, pyfile_extes

其他回答

扩展Mihail的回答,我认为非黑客的方式(即不直接处理文件路径)如下:

在Foo/下创建一个空的__init__.py文件 执行

import pkgutil
import sys


def load_all_modules_from_dir(dirname):
    for importer, package_name, _ in pkgutil.iter_modules([dirname]):
        full_package_name = '%s.%s' % (dirname, package_name)
        if full_package_name not in sys.modules:
            module = importer.find_module(package_name
                        ).load_module(full_package_name)
            print module


load_all_modules_from_dir('Foo')

你会得到:

<module 'Foo.bar' from '/home/.../Foo/bar.pyc'>
<module 'Foo.spam' from '/home/.../Foo/spam.pyc'>

看看标准库中的pkgutil模块。只要目录中有__init__.py文件,它就会让你做你想做的事情。__init__.py文件可以为空。

何时从。Import *不够好,这是对ted的回答的改进。具体来说,这种方法不需要使用__all__。

"""Import all modules that exist in the current directory."""
# Ref https://stackoverflow.com/a/60861023/
from importlib import import_module
from pathlib import Path

for f in Path(__file__).parent.glob("*.py"):
    module_name = f.stem
    if (not module_name.startswith("_")) and (module_name not in globals()):
        import_module(f".{module_name}", __package__)
    del f, module_name
del import_module, Path

请注意,globals()中没有module_name是为了避免在已经导入模块时重新导入模块,因为这可能存在循环导入的风险。

列出当前文件夹中的所有python (.py)文件,并将它们作为__init__.py中的__all__变量

from os.path import dirname, basename, isfile, join
import glob
modules = glob.glob(join(dirname(__file__), "*.py"))
__all__ = [ basename(f)[:-3] for f in modules if isfile(f) and not f.endswith('__init__.py')]

我已经为此创建了一个模块,它不依赖于__init__.py(或任何其他辅助文件),并让我只输入以下两行:

import importdir
importdir.do("Foo", globals())

请随意重用或贡献:http://gitlab.com/aurelien-lourot/importdir