从模块的外部用户的角度来看,都是必要的吗?
根据我的理解,通过使用下划线正确地加上隐藏函数前缀,它基本上与显式定义__all__
完全相同,但我一直看到开发人员在他们的代码中做了两件事。那是为什么?
答案 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_call
和os
,并且在使用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__
。无论什么时候你需要它做不寻常的事情,那么这样做是有意义的。