如何调用包内的所有模块?

How to Call All Modules inside Package?

我有一个具有此层次结构的项目

tasker/
        table/
                __init__.py
                user.py
                task.py
                ...
        __init__.py
        tasker.py

table 文件夹中的每个文件(__init__.py 除外)都包含一个与文件名同名的 class,只是第一个字母大写。我想调用并实例化 tasker.pytable 文件夹中的每个 class。我可以写

import table

里面 tasker.py。但是,事实证明我必须写例如

table.user.User()

user.py里面实例化class,看起来很丑。有什么方法可以让我至少输入

user.User()

甚至更好,

User()

实例化那些 classes?

注意:table 文件夹中的每个文件都是动态更改的。我可能会在 table 文件夹中添加或删除文件。

这可能有效

from table import user

user.User()

我建议自动完成大部分工作。您可以在 tasker.table.__init__:

中注册您感兴趣的模块
table_registry = ['user', 'task', ...]

此时您不需要导入任何东西,我不建议使用 __all__,因为它完全有不同的用途。使用手动创建列表的好处是您的包可以包含其他模块而不会受到任何干扰。

现在 tasker.tasker 可以动态完成所有工作:

from .table import table_registry
from importlib import import_module

pkg = 'tasker.table'
for name in table_registry:
    mod = import_module('.' + name, package=pkg)
    name = name.titlecase()
    # Check if module contains uppercased class name
    if hasattr(mod, name):
        cls = getattr(mod, name)
        # Check if it's a class
        if isinstance(cls, type):
            # Assign to current module
            globals()[name] = cls

del name, mod, cls

如果您不想手动注册您感兴趣的模块,您可以使用 pkgutil 中的实用程序动态发现它们。在此版本中,tasker.table.__init__ 可以保留为空。 tasker.tasker 会得到这样的模块列表:

from pkgutil import walk_packages
from importlib import import_module

for info in walk_packages(tasker.table.__path__, prefix='tasker.table.'):
    if info.ispkg: continue
    mod = import_module(info.name)
    name = info.name.split('.')[-1].titlecase()
    if hasattr(mod, name):
        ...

其余代码与手动版本相同。此版本将递归到它找到的任何子包中。只要您不对 __path__ 属性做任何疯狂的事情,它就会正常工作。

您可以使用星号一次性导入包内的所有模块:

from table import *