__init__.py的用法

7
我使用__init__.py在执行from myprojects.something import blabla时运行检查。
今天我开始使用pyzmq,想要查看其背后的运行机制。于是我浏览了github上的代码,发现(对我来说)一些奇怪的__init__.py用法,我自己也无法解释。
例如zmq/core/__init__.py。在zmq.core.__all__中添加__all__的值为zmq.core.constants、zmq.core.error、zmq.core.message等有什么意义呢?
zmq/__init__.py中,我在结尾处看到:
__all__ = ['get_includes'] + core.__all__

get_includes是一个函数,它基本上返回一个列表,其中包括模块的目录和父目录中utils目录。

那么这有什么意义呢?__init.py__通过这样做实现了什么?

1个回答

14
< p > __all__ 是为了当有人执行 from module import * 操作时使用,具体文档请参见这里

唯一的解决方案是由包作者提供一个明确的包索引。导入语句使用以下约定:如果一个包的 __init__.py 代码定义了一个名为 __all__ 的列表,则会将其视为在遇到 from package import * 时应该导入的模块名称列表。当发布新版本的包时,包的作者需要保持此列表最新。如果包作者不认为从其包中导入*有用,他们也可以选择不支持它。例如,文件 sounds/effects/__init__.py 可能包含以下代码:

__all__ = ["echo", "surround", "reverse"]

这意味着from sound.effects import *会导入声音包的三个已命名子模块。

__all__的一个用途是作为打包者的工具,允许他们以适合自己的方式构建其包,同时方便用户使用。特别是在pyzmq的情况下,它使您可以编写如下代码:

import zmq
print zmq.zmq_version()

与其使用完整的点分模块名:

print zmq.core.version.zmq_version()

在pyzmq的包设计中,设计者使用__all__来将嵌套模块中的命名空间元素提升到顶层命名空间,以便用户不会被包的结构所困扰。


在向这里提问之前,我已经阅读了文档的这一部分。但是这仍然没有回答我的问题。也许我应该换一种方式问:我认为使用 from bla import ble 的原因是你可以控制你的命名空间,这意味着你可以决定将哪些符号添加到你的命名空间中。 - Pablo
与C语言相反的是,在C语言中使用#include可能会与已定义的函数、变量等发生冲突,因此应该只导入您真正需要的符号。我曾经在Python文档中读到过使用from bla import *不是一个好习惯,如果是这样的话,那么为什么还要定义__all__呢?当使用import *时,__all__ = ['get_includes'] + core.__all__如何被评估? - Pablo
1
从bla导入*不是一个好习惯,但有一些模块通常是安全的。我经常使用from math import 。这些模块的文档通常指出它们被设计为以这种方式使用,并支持__all__等便利功能,使其更容易。但是,从x导入仍然需要谨慎使用,只能在您知道它不会引起问题的包中使用。 - TimothyAWiseman
@John Gaines Jr:你最后的编辑非常有道理。我问自己为什么能够使用zmq.REQ,即使REQ已经在core.constants中定义了。感谢你的分享。 - Pablo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接