每当我想搞透一个东西的时候,我就会写篇文章。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 *
在此示例中,echo
和surround
模块被导入当前名称空间中,因为它们在执行语句sound.effects
时在包中定义from...import
。(这在__all__
定义时也适用 。)
尽管某些模块被设计为仅在使用时导出遵循某些模式的名称,但在生产代码中import *
仍被认为是不好的做法。
记住,使用from package import specific_submodule
没什么错。实际上,这是推荐的表示法,除非导入模块需要使用来自不同软件包的具有相同名称的子模块。
网友评论