如何在模块中定义与 __all__ 分开的 `from ... import *` API?

6 投票
4 回答
1199 浏览
提问于 2025-04-16 23:38

我有一个模块,这个模块大致分为两部分:一部分是一些工具函数,另一部分是核心的API函数。我需要把所有这些函数都放在__all__里,这样才能让help()这个功能好用,同时也能明确哪些函数、类等是可以被外部使用的。不过,我也想支持from mymodule import *这种方式,这样可以只把核心功能导入到其他模块中。请问有没有办法做到这一点呢?

4 个回答

2

我觉得没有办法做到这一点,至少没有什么好的方法。就连Python官方的模块里也有很多实用的函数出现在文档中。如果你觉得分开很重要,我建议你创建两个不同的模块。总之,使用 from module import * 这种写法并不是个好习惯,我不推荐你这么做,更不建议你为了这种写法来设计你的模块 :)

4

Ethan,你的 fake_module 其实用普通的Python就能更好地实现。只需要把你的代码放到一个目录结构里:

mymodule
    __init__.py
    api.py
    util.py
    _mymodule.py

其中 _mymodule.py 里放的是你现在的代码。

在你的 __init__.py 文件里:

from _mymodule import * 

在你的 api.py 文件里:

# explicity import only those api classes you want to expose
# this will allow you to call `from mymodule.api import *`
import from _mymodule ApiClass1
import from _mymodule ApiClass2
# etc  

对你的 util.py 文件也这样做:

# explicity import only those util classes you want to expose
# this will allow you to call `from mymodule.util import *`
import from _mymodule UtilClass1
import from _mymodule UtilClass2
# etc

这样你就可以:

# import everything willy nilly for your help()
from mymodule import *

# or import only the "public" values from api and util
from mymodule.api import *
from mymodule.util import *

把代码分开这样做,可以帮助你更好地组织一个比较大的模块,同时又能从顶层命名空间访问它。不过我同意 brandizzi 的看法,在使用这个模块的代码里用 from mymodule import * 通常不是个好主意。你在导入时的方便,可能会让使用这些导入的代码变得不那么清晰。

5

差不多。不过,虽然你不能让 __all__ 同时起到两个作用,但你可以添加一个自己的虚拟 API 模块,这样就可以导入它了...

class fake_module(object):
    def __init__(self, name, *args):
        self.name = name
        self.__all__ = []
        all_objects = globals()
        for name in args:
            self.__dict__[name] = all_objects[name]
            self.__all__.append(name)
    def register(self):
        sys.modules["%s.%s" % (__name__, self.name)] = self

    fake_module('api', 'class1', 'class2', 'func3', 'exception4').register()

然后在其他模块中,不用写 from mymodule import *,而是可以写 from mymodule.api import *,这样就能只获取你想要的部分,同时还可以把所有东西放在一个模块里。

注意: from ... import * 通常不是一个好的做法,使用时要非常小心,并且只在那些明确说明可以这样使用的模块或包中使用。

撰写回答