我是否应该定义__all__,即使我在模块中使用下划线作为隐藏函数和变量的前缀?

时间:2013-12-02 18:05:32

标签: python

从模块的外部用户的角度来看,都是必要的吗?

根据我的理解,通过使用下划线正确地加上隐藏函数前缀,它基本上与显式定义__all__完全相同,但我一直看到开发人员在他们的代码中做了两件事。那是为什么?

3 个答案:

答案 0 :(得分:7)

从带有下划线的from modulename import *名称的模块导入时确实会跳过。

但是,模块很少包含公共API对象。通常,您也进行了导入以支持代码,并且这些名称在模块中也是全局的。如果没有__all__,那些名称也将成为导入的一部分。

换句话说,除非您想在以下示例中“导出”os,否则应使用__all__

import os
from .implementation import some_other_api_call

_module_path = os.path.dirname(os.path.abspath(__file__))
_template = open(os.path.join(_module_path, 'templates/foo_template.txt')).read()

VERSION = '1.0.0'

def make_bar(baz, ham, spam):
    return _template.format(baz, ham, spam)

__all__ = ['some_other_api_call', 'make_bar']

因为没有__all__列表,Python无法在此处区分some_other_api_callos,并且在使用from ... import *时不应该导入哪一个。

您可以通过重命名所有导入来解决此问题,因此import os as _os,但这只会降低您的代码的可读性。

显式导出列表总是很好。正如Python的Zen告诉你的那样,明确比隐含更好。

答案 1 :(得分:1)

我还使用__all__明确告诉模块用户您要导出的内容。在模块中搜索名称是很乏味的,即使你小心谨慎,例如import os as _os等。一个聪明的人曾写过“明确比隐含更好”; - )

答案 2 :(得分:0)

定义all将覆盖默认行为。实际上可能有一个理由来定义__all__

导入模块时,您可能希望from mod import *仅导入少量内容。即使您正确地为所有内容添加前缀,也可能有理由不导入所有内容。

我曾经遇到的另一个问题是定义gettext快捷方式。翻译函数为_,无法导入。即使它“在理论上”加上前缀,我仍然希望它能够被导出。

如上所述的另一个原因是导入导入很多东西的模块。因为python无法区分导入创建的符号和实际模块中定义的符号。它会自动重新导出可以重新导出的所有内容。因此,明确限制导出到您要导出的内容的东西是明智的。

考虑到这一点,您可能希望默认导出一些带前缀的符号。通常,您不会重新定义__all__。无论什么时候你需要它做不寻常的事情,那么这样做是有意义的。