@ghimi
2018-10-09T07:20:46.000000Z
字数 2191
阅读 740
Python
包
为了组织好模块,会将多个模块分为包.Python处理包也是相当方便的.简单来说,包就是文件夹,但该文件夹下必须存在__init__.py
文件.
常见的包结构如下:
package_a
|-------__init__.py
|-------moudle_a1.py
|-------moudle_a2.py
最简单的情况下,值需要一个空的 __init__.py
文件即可.当然它也可以执行包的初始化代码,或者定义稍后介绍的 __all__
变量.当然包
底下也能包含 包
,这个文件夹一样,还是比较好理解的.
包的导入仍使用 import,from ... import,使用"圆点模块名"的结构化模块命名空间.下面来看一个包的例子来了解下具体的运作.
假设你现在想要设计一个模块集(一个"包")来统一处理声音文件和声音数据.存在几种不同的声音格式(通常由它们的拓展名来标识,例如: .wav,.aiff,.au)于是,为了在不同类型的文件格式之间转换,你需要维护一个不断增长的包集合.可能你还想要对声音数据做很多不同的操作(例如混音,添加回声,应用平衡功能,创建一个人造效果)所以你要加入一个无限流模块来执行这些操作.你的包可能会是这个样子(通过分级的文件体系来进行分组):
sound Top-level package
|---------- __init__.py Initialize the sound package
|---------- formats Subpackage for file format conversions
| |-------- __init__.py
| |-------- wavread.py
| |-------- wavwrite.py
| |-------- aiffread.py
| |-------- aiffwrite.py
| |-------- auread.py
| |-------- auwrite.py
| |-------- ....
|---------- effects Subpackage for sound effects
| |-------- __init__.py
| |-------- echo.py
| |-------- reverse.py
| |-------- ...
|---------- filters Subpackage for filter
| |-------- __init__.py
| |-------- equalizer.py
| |-------- vocoder.py
| |-------- karaoke.py
用户可以每次只导入包里的特定模块,例如:import sound.efforts.echho
这样就导入了 sound.effects.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()函数:
echo.echofilter(input,output,delay=0.7,atten=4)
需要注意的是 from package import item
方式导入包时,这个子项(item)既可以是子包也可以是其他命名,如函数,类,变量等.若无,会引发ImportError
异常.
而用类似 import item.subitem.subsubitem
这样的语法时,这些子项必须是包,最后的子项可以是包或模块,但不能是类,函数,变量等.
import * 这样的语句理论上是希望文件系统找出保重所有的子模块,然后导入它们.这可能会花很长时间,并出现边界效应等.Python 解决方案是提供一个明确的包索引.
这个索引由 __init__.py
定义 __all__
变量,该变量为一列表,如上例 sound/effects
下的 __init__.py
,可定义 all = ["echo","surround","reverse"]
这意味着,from sound.effects import *
会从对应的包中导入以上三个子模块;尽管提供 import *
的方法,仍不建议在生产代码中使用这种写法.
如果是子包内的引用,可以按相对位置引入子模块以 echo 模块为例,可以引用如下:
from . import reverse # 同级目录 导入 reverse
from .. import frormats # 上级目录 导入 formats
from ..filters import equalizer # 上级目录的 filters 模块下 导入 equalizer
包支持一个更为特殊的特性,__path__
在包的 __init__.py
文件代码执行前,该变量初始化一个目录名列表.作用于子包和模块的搜索功能.该功能可以用于扩展保重的模块集,不过不常用.