模块Module

Lean from python2.7 official documentation

使用文本编辑器编写文件,并将其作为解释器(interpreter)的输入,这样的文件叫做脚本(script)。随着程序越来越长,将脚本拆分成几个文件更利于维护,为此,Python提供将定义写入一个文件中,并在脚本或者解释器中使用它们的方法,这样的文件称作模块(module)。

模块是一个包含Python定义和语句的文件,文件名为模块名加后缀.py

模块名(作为一个字符串)可以通过全局变量__name__来获得。

6.1 更多有关模块的信息

模块包含的语句以及函数定义,用于模块的初始化,仅在模块第一次在import语句中被导入时才执行。(当文件被当作脚本运行时,它们也会执行。)

每个模块都有自己的私有符号表(private symbol table),作为模块中定义的所有函数的全局符号表。模块的作者可以在模块内使用全局变量(global variables),而不必担心与用户的全局变量冲突。

习惯上把所有导入模块的import语句放在脚本或模块的开头,被导入的模块名存放在全局符号表中。

import语句有一个变体,它可以把模块符号表中存在的name直接导入到脚本或模块中,而不会把被调模块名引入当前的符号表:

1
2
from fibo import fib
fib(500)

使用*可以导入模块内定义的,除了以下划线_开头的所有name

1
from fibo import *

使用as可以为引入的模块或模块内名称添加昵称:

1
2
3
4
5
import fibo as fb
fb.fib(500)

from fibo import fib as fb
fb(500)

6.1.1 以脚本方式执行模块

使用python命令运行.py模块时,模块里的代码会被执行,且__name__会被赋值为"__main__"

通过手动在模块末尾添加:

1
2
3
if __name__ == "__main__":
import sys
fib(int(sys.argv[1]))

可以既把这个文件当作脚本又把它当作一个可调入的模块来使用,这段解析命令行(详见sys.argv)的代码只有在当模块是以“main”文件的方式执行的时候才会运行,如果模块是被导入的,这段代码是不运行的。这种方法多用于以脚本的方式运行模块从而执行一些测试套件。

6.1.2 模块搜索路径

当一个名为 spam 的模块被导入的时候,解释器首先寻找具有该名称的内置模块(built-in module)。如果没有找到,解释器将从 sys.path 变量给出的目录列表里寻找名为 spam.py 的文件。sys.path初始有这些目录地址:

  • 包含输入脚本(input script)的目录或当前的目录;
  • PYTHONPATH:一个由目录名组成的列表,目录名的语法与shell中的PATH变量相同;
  • 与安装相关的(installation-dependent)系统默认值。

包含正在运行脚本的文件目录被放在搜索路径sys.path的开头处, 在标准库路径之前。这意味着将加载此目录里的脚本,而不是标准库中的同名模块。

6.2 标准模块Standard Module

Python附带了一个标准模块库(library of standard modules),这些模块内置于解释其中,它们提供对那些不属于语言的核心(the core of the language)但仍然内置的(built in)操作的访问以提高效率,或提供对系统调用(system calls)等操作系统原语(operating system primitives)的访问。

其中值得注意的模块sys,它被内嵌到每一个Python解释器(无论在哪一种操作系统)。

使用标准列表操作(standard list operations)可以对sys.path进行修改:

1
2
import sys
sys.path.append('/ufs/guido/lib/python')

6.3 dir()函数

内置函数 dir([object])用于查找已被定义名称的列表,返回的列表按字母表排序。

如果没有实参,dir()返回当前本地作用域中的名称列表;

如果有实参, dir(object)返回object对象包含的有效属性列表。

注意:列表中包含所有类型的名称:变量,模块,函数,等等。

如果要获取内置函数和变量的名称,可以使用:

1
2
import __builtin__
print dir(__builtin__)

6.4 包Package

包是一个分层次的文件目录结构,它定义了一个由模块及子模块,和子模块下的子模块等组成的Python的应用环境。

简单来说,包就是文件夹,但该文件夹下必须存在__init__.py文件, 该文件的内容可以为空。__init__.py用于标识当前文件夹是一个包。

考虑以下目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
sound/                          Top-level package
__init__.py Initialize the sound package
formats/ Subpackage for file format conversions
__init__.py
wavread.py
...
effects/ Subpackage for sound effects
__init__.py
echo.py
surround.py
reverse.py
...
filters/ Subpackage for filters
__init__.py
equalizer.py
...

包的用户可以从包中导入单个模块,

使用下面的语句加载子模块文件/sound/effects/echo.py,引用时必须使用全名sound.effects.echo

1
2
import sound.effects.echo
sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)

使用另一种方法导入子模块echo,可以在没有包前缀的情况下使用它:

1
2
from sound.effects import echo
echo.echofilter(input, output, delay=0.7, atten=4)

同样,可以使用from package import item语句,直接从子模块中导入函数,类或变量:

1
2
from sound.effects.echo import echofilter
echofilter(input, output, delay=0.7, atten=4)

6.4.1 从包中导入 *

如果一个包的__init__.py文件中,定义了一个名为__all__的列表,它会被视为在遇到from package import *语句时应该导入的模块名列表。

在发布该包的新版本时,包作者可以决定是否让此列表保持更新。包作者如果认为从他们的包中导入 * 的操作没有必要被使用,也可以决定不支持此列表。

以前文中的目录结构为例,/sound/effects/__init__.py文件可以包含如下的列表:

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

这样,在使用from sound.effects import *语句时,将导入列表中的三个子模块。

6.4.2 包内引用Intra-package References

当包内的模块想要引用本包内的其他模块时,可以使用绝对引用(absolute imports)和相对引用(relative imports)。

以前文中目录结构为例,如果sound.filters.equalizer想要使用sound.effects.echo模块,可以使用绝对引用:

1
from sound.effects import echo

如果sound.effects.surround想要使用包内引用,可以进行下面的相对引用:

1
2
3
4
5
6
7
8
#引用整个sound.formats子包
from .. import formats

#引用同目录下的模块echo.py
from . import echo

#引用兄弟包的子模块(submodules of siblings packages)
from ..filters import equalizer

6.4.3 多个目录Multiple Directories中的包

包支持另一个特殊属性,__path__。它被初始化为一个列表,其中包含在执行该文件中的代码之前,保存包文件__init__.py的目录名称。

这个变量可以修改;这样做会影响将来对包中包含的模块和子包的搜索。