python的__init__.py文件

每当我想搞透一个东西的时候,我就会写篇文章。OK,今天的主题就是这个__init__文件。
关于这个文件,问题无非是三个,是什么,为什么,怎么用。

是什么- python包管理

这个问题的核心在于python的包管理。
python使用包来组织模块的命名空间。A.B表名在A包中的B模块。主要用来解决全局变量名称冲突的问题。

为什么

来看一个典型的项目结构:

image.png

在导入一个包的时候,python搜索所有sys.path下面的目录。__init__.py文件用来告诉python,这个目录是一个python包。
这个机制防止某些通用名字的目录,例如string,和后续加载的实际可能的模块名发生冲突。

怎么用

import语句

最简单的情况下,__init__.py文件可以是空的。也可以执行初始化代码,或者设置__all__变量。

包的用户可以导入包中的单独的某个模块,例如:
import sound.effcts.echo
这会加载子模块sound.effcts.echo,使用时必须使用全名:
sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)

另外一种导入包的方式是:
from sound.effects import echo
这也会加载子模块echo, 使用时不需要使用全名:
echo.echofilter(input, output, delay=0.7, atten=4)

也可以直接导入某个函数:
from sound.effects.echo import echofilter
这会加载子模块echo,但是函数echofilter()直接可用:
echofilter(input, output, delay=0.7, atten=4)

在使用from package import item语法时,item可以是package的子模块、子包或者任何定义在packge里的名字。例如一个函数、类或变量。import声明首先假设item是package里定义的,如果不是,会假设他是一个模块并尝试加载。加载失败会抛出importerror.

使用import item.subitem.subsubitem的时候,除了嘴后一个Item,其他的Item都必须是包。最后一个item可以是一个模块,一个包,但不能是类或者函数、变量。

import * from a package

当用户书写from sound.effects import *时会发生什么?理想情况下,这种方式能进入文件系统,找到程序包中存在哪些子模块,然后将其全部导入。这可能会花费很长时间,并且导入子模块可能会产生有害的副作用,这些副作用只有在明确导入子模块时才会发生。

唯一的解决方案是让程序包作者提供程序包的显式索引。该import语句使用以下约定:如果程序包的 __init__.py代码定义了名为的列表__all__,则将其视为遇到时应导入的模块名称的列表。发行新版本的软件包时,软件包作者有责任使此列表保持最新。如果软件包作者看不到从软件包中导入*的用途,他们可能还会决定不支持它。例如,该文件可能包含以下代码:

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

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

如果__all__没有定义,语句 也不会导入从包中的所有子模块到当前的命名空间; 它仅确保已导入包sound.effects(可能运行__init__.py中任何初始化代码),然后导入包中定义的任何名称。这包括由__init__.py定义的任何名称(以及明确加载的子模块)。它还包括程序包的所有子模块,这些子模块由先前的语句显式加载。考虑以下代码:
import sound.effects.echo
import sound.effects.surround
from sound.effects import *
在此示例中,echosurround模块被导入当前名称空间中,因为它们在执行语句sound.effects时在包中定义from...import。(这在__all__定义时也适用 。)

尽管某些模块被设计为仅在使用时导出遵循某些模式的名称,但在生产代码中import *仍被认为是不好的做法。

记住,使用from package import specific_submodule没什么错。实际上,这是推荐的表示法,除非导入模块需要使用来自不同软件包的具有相同名称的子模块。

你可能感兴趣的:(python的__init__.py文件)