Modules
在Python的解释器中实时输入和输出,当你退出解释器时,你定义的函数和变量就会丢失。所以,如果你想写一个长点的应用程序,最好用编辑器去写你想输入到解释器的东西。这就是大家说的写一个脚本。当程序变的很长了,为了维护方便,你就会想把它拆解到几个文件里。你或许还想定义一个简单的可复用的函数,防止在其它多个程序里重复拷贝。
Python支持你将这些定义放入一个文件,然后在一个脚本或者在解释器的交互实例中使用他们,这样的一个文件就是一个module。module中的定义可以被导入到其它的module中或者主module中。
一个module是一个文件包含Python定义和表述。文件的命名就是模块名.py。在一个module中,模块的名字可以通过一个全局变量__name__来获得。
例如,用编辑器创建一个文件fibo.by,内容如下:
def fib(n): # write Fibonacci series up to n
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a+b
print()
def fib2(n): # return Fibonacci series up to n
result = []
a, b = 0, 1
while a < n:
result.append(a)
a, b = b, a+b
return result
则输出为:

更多关于Module的介绍
一个module不仅可以包含函数定义还可以包含可执行的表述。这些表述可以用来初始化module。它们近在第一次import的时候或者这个脚本被执行时执行。
模块还可以导入其它模块,当你的模块有更新的时候,你需要重新导入或者load这个module。
像脚本一样执行module __main__
当我们如下执行没有事情发生,不像我们import它之后可直接调用。如果我们想像import以下而执行该脚本,则
python fibo.py
如果我们想像import了该module而执行该脚本,则需要更改代码如下:
def fib(n): # write Fibonacci series up to n
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a+b
print()
def fib2(n): # return Fibonacci series up to n
result = []
a, b = 0, 1
while a < n:
result.append(a)
a, b = b, a+b
return result
if __name__ == "__main__":
import sys
fib(int(sys.argv[1]))
则执行结果为:
![]()
当我们在命令行运行该脚本时,该模块作为主模块执行,而当被import时,该模块不是主模块,则不会被执行。
我们这样做的好处是提供一个方便的用户的模块接口,或者为了执行测试。
模块的搜索路径 sys.path
当你试图导入一个叫spam的模块,解释器会首先搜索内部模块,如果内部模块中没有这样的模块名,则在sys.path的一系列目录中查找是否有命名为spam.py的文件。sys.path通常初始化为:
- 当前目录
- PYTHONPATH
- 默认安装依赖的路径
找到后更改下sys.path, 把它放去当前目录的路径中。
编译后的Python文件
为了加速去加载模块,Python高速缓存每一个编译的module放到__pycache__目录下,命名为moudle-python version.pyc。Python检测源码的编辑日期来判断是否需要重新编译。这是一个自动过程。编译后的模块与平台无关,在不同的系统之间可以共享。
Python在以下两种情况不会去检测高速缓存:
- 总是编译但是并不存储
- 没有源码的模块(在非源码分发中,编译好的模块必须位于源码目录)
一些更高深一些的建议:
- 可使用-0/-00开关去减少编译模块的大小。-0移除了断言,-00移除了断言和文档说明。有一些程序需要断言和文档说明,有些并不需要,请根据需要控制开关。优化后的模块通常有‘opt’标签并会小一些。
- 高速缓存并不会使该模块执行的速度加快,而只会加快其被加载时的时间。
- compileall模块会编译目录中所有的模块
- 针对这一过程,更详细的流程介绍,可参见 PEP 3147.
Packages
Packages是一种组织Python模块命名空间的方法。例如,一个模块为A.B指明子模块B在包A中。
假定我们要开发一个处理声音文件和数据的包。需要支持:
- 处理不同的文件格式
- 支持不同的声音效果
- 支持其它定制和花样选择
则我们可以定义的目录结果为:
(.jira_helper) [wlin@MiWiFi-R4A-srv sound]$ tree
.
|-- effects
| |-- echo.py
| |-- __init__.py
| `-- surround.py
|-- filters
| |-- __init__.py
| `-- vocoder.py
|-- formats
| |-- __init__.py
| `-- wavread.py
`-- __init__.py
3 directories, 8 files
当importing包时,Python会按照sys.path去找package。当目录下含有"__init__.py"文件时,Python将其看为包,这样__init__.py的层级结构就表明了包的层级结构,如上目录结构,我们可以如下调用:
In [1]: import sound.
sound.effects sound.filters sound.formats
In [1]: import sound.effects
sound.effects
In [1]: import sound.effects.
sound.effects.echo sound.effects.surround
In [1]: import sound.effects.echo
In [1]: from sound.effects.echo import ECHO
In [2]: ECHO
Out[2]: 'Aha..'
In [3]: from sound.effects.echo import echo
In [4]: echo()
Echo Function
如上,当使用 import item时,只能import到module或者package, 无法import到变量和函数。而使用from module/package后则可以引用到变量和函数。
关于importing *
我们希望通过importing *引入所有包中的子模块,但实际上,除了使加载时间变长,且会让情况变的很难控制,它会加载这个模块中所有的定义在该模块中的名字。
所以,我们尽量不单独使用import *, 而使用准确引入。而子模块很多,确实想使用import *, 则需要在__init__.py定义__all__=['module1','module2'...]即可。
内部包引用
如sound包,sound.filters.vecoder需要用echo.effects中的模块,则可以使用绝对路径引用‘from sound.effects import echo’,也可以使用相对路径 ‘from . import echo’或者 'from .. import formats'
则定义为:
from . import surround
from ..filters import vocoder
def echo():
print("Echo Function")
surround.echo()
vocoder.echo()
ECHO = "Aha.."
输出为:
In [2]: from sound.effects import echo
In [3]: echo.echo()
Echo Function
Hello surround function
Hello vecoder function
切记,相对路径时相对于当前模块。
Python的Modules是可执行的文件,用于组织代码,可通过import导入。__name__变量标识模块是否为主模块。搜索模块路径sys.path包括当前目录、PYTHONPATH和默认安装路径。编译后的模块存储在__pycache__中。Packages是模块的命名空间组织方式,通过__init__.py定义层级,import *应谨慎使用,可定义__all__控制导入。内部包引用支持绝对和相对路径。

366

被折叠的 条评论
为什么被折叠?



