Python编程入门(5)
第六章 模块
如果退出Python解释程序然后再进入,原有的定义(函数和变量)就丢失了。所以,如果需要写长一点的程序,最好用一个文本编辑程序为解释程序准备输入,然后以程序文件作为输入来运行Python解释程序,这称为准备脚本(script)。当你的程序变长时,最好把它拆分成几个文件以利于维护。你还可能想在几个程序中都使用某个很方便的函数,但又不想把函数定义赋值到每一个程序中。
为了支持这些,Python有一种办法可以把定义放在一个文件中然后就可以在一个脚本中或交互运行中调用。这样的文件叫做一个模块;模块中的定义可以导入其它模块或主模块(主模块指在解释程序顶级执行的脚本或交互执行的程序所能访问的变量集合)。
模块是包含了Python定义和语句的文件。文件名由模块名加上后缀“.py”构成。在模块内,模块的名字(作为一个字符串)可以由全局变量__name__的值获知。例如,在Python的搜索路径中用你习惯使用的文本编辑器(Python 1.5.2包含了一个用Tkinter编写的IDLE集成开发环境,MS Windows下有一个PythonWin界面也可以进行Python程序编辑)生成一个名为“fibo.py ”的文件,包含如下内容:
# Fibonacci numbers module
def fib(n): # 输出小于n的Fibonacci序列
a, b = 0, 1
while b < n:
print b,
a, b = b, a+b
def fib2(n): # 返回小于n的Fibonacci序列
result = []
a, b = 0, 1
while b < n:
result.append(b)
a, b = b, a+b
return result然后进入Python解释程序(在IDLE或PythonWin中可以直接进入解释程序窗口),用如下命令可以导入模块:
>>> import fibo
这不会把模块fibo中的函数的名字直接引入当前的符号表,这只是把模块名fibo引入。可以用模块名来访问其中的函数:
>>> fibo.fib(1000)
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>> fibo.fib2(100)
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
>>> fibo.__name__
fibo如果经常使用某个函数可以给它赋一个局部名字:
>>> fib = fibo.fib
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 3776.1 模块的进一步介绍
模块除了可以包含函数定义之外也可以包含可执行语句。这些可执行语句用来初始化模块,它们只在模块第一次被导入时执行。
每个模块有自己私有的符号表,这个私有符号表对于模块中的所有函数而言却是它们的全局符号表。因此,模块作者可以在模块中使用全局变量而不需担心与模块用户的全局变量冲突。另一方面,如果你有把握的话也可以用访问模块中函数的格式,即modname.itemname的方法来修改模块中的全局变量。
模块可以导入其它模块。我们通常把所有的导入语句放在模块(或脚本)的开始位置,这不是规定要求的。导入的模块名放入模块的全局符号表中。
导入还有另一种用法,可以把模块中的名字直接导入使用者的符号表。例如:
>>> from fibo import fib, fib2
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377这不会把模块名导入使用者的符号表中(例如,上面例子中fibo就没有定义)。
还有一种办法可以导入一个模块中定义的所有名字:
>>> from fibo import *
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377这可以把模块中除了以下划线结尾的所有名字导入。
6.1.1 模块搜索路径
在导入名为spam的模块时,解释程序先在当前目录中寻找名为“spam.py”的文件,然后从环境变量PYTHONPATH所定义的目录列表中寻找。PYTHONPATH的用法和可执行文件的搜索路径PATH用法相同,都是一个目录列表。当PYTHONPATH未设置的时候,或者文件仍找不到,则搜索继续在安装时设定的缺省路径搜索,在Unix中,这通常是“.:/usr/local/lib/python” 。
实际上,模块是按变量sys.path指定的路径搜索的,此变量在解释程序启动时初始化为包含输入脚本的目录(或当前路径),PYTHONPATH和安装缺省路径。这样,用户可以通过修改sys.path 来修改和替换模块搜索路径。参见后面关于标准模块的一节。
6.1.2 “编译”的Python文件
为了提高调用许多标准模块的小程序的启动时间,一个重要的措施是,如果在找到“spam.py ”的目录中存在一个名为“spam.pyc”的文件,就认为此文件包含了模块spam的一个所谓“ 字节编译”版本。用于生成“spam.pyc”的“spam.py”的修改时间被记入了“spam.pyc”中,如果记录的修改时间与现在文件的时间不相符的话就忽略编译文件。
一般不需要自己生成“spam.pyc”这样的编译文件。每当“spam.py”成功编译后解释程序就尝试写编译版本“spam.pyc”,如果不可写也不会出错;如果因为某种原因此文件没有写完则生成的“spam.pyc”被识别为不完整的而被忽略。编译文件“spam.pyc”的格式是不依赖于平台的,所以不同结构的机器可以共享Python模块目录。
下面是对专家的一些窍门:
如果Python解释程序是以-O标志启动的,将生成优化的编译代码,保存在“.pyo”文件中。目前优化不是很多,现在只是去掉assert语句和SET_LINENO指令。使用了-O标志时,所有字节码都是优化的,“.pyc”文件被忽略,“.py”文件被编译为优化的字节码。
给Python解释程序两个优化标志(-OO)产生的优化代码有时会导致程序运行不正常。目前双重优化只从字节码中删除了__doc__字符串,使得“.pyo”文件较小。有些程序可能是依赖于文档字符串的,所以只有在确知不会有问题时才可以使用这样的优化。
从“.pyc”或“.pyo”读入的程序并不能比从“.py”读入的运行更快,它们只是调入速度更快一些。
如果一个程序是用在命令行指定脚本文件名的方式运行的,脚本的字节码不会写入“.pyc ”或“.pyo”文件。所以如果把程序的主要代码都移入一个模块,脚本中只剩下导入该模块的引导程序则可以略微缩短脚本的启动时间。
可以有叫做“spam.pyc”(当用了-O标志时为“spam.pyo”)的文件而没有对应的源文件“spam.py”。这可以用来分发一个比较难反编译的Python代码库。
模块compileall可以把一个目录中所有模块编译为“.pyc”文件(指定了-O选项时编译为“.pyo”文件)。
6.2 标准模块
Python带有一个标准模块库,在另一个文档《Python库参考》中进行了描述。一些模块直接编入了解释程序中,这些模块不是语言的核心,为了运行效率或者为了提供对于系统调用这样的系统底层功能而编入了解释程序中。提供那些模块是编译时的选择,例如,amoeba模块只在提供amoeba底层指令的系统中才能提供。
有一个模块值得特别重视:sys模块,每一个Python解释程序中都编译入了这个模块。变量sys.ps1和sys.ps2定义了交互运行时的初始提示和续行提示。
>>> import sys
>>> sys.ps1
>>>
>>> sys.ps2
...
>>> sys.ps1 = C>
C> print Yuck!
Yuck!
C>这两个变量只在解释程序以交互方式运行时才有定义。
变量sys.path是一个字符串列表,由它确定解释程序的模块搜索路径。它被初始化为环境变量PYTHONPATH所指定的缺省路径,环境变量没有定义时初始化为安装时的缺省路径。可以用标准的列表操作修改这个搜索路径,例如:
>>> import sys
>>> sys.path.append(/ufs/guido/lib/python)6.3 dir()函数
内置函数dir()用于列出一个模块所定义的名字,它返回一个字符串列表:
>>> import fibo, sys
>>> dir(fibo)
[__name__, fib, fib2]
>>> dir(sys)
[__name__, argv, builtin_module_names, copyright, exit,
maxint, modules, path, ps1, ps2, setprofile, settrace,
stderr, stdin, stdout, version]没有自变量时,dir()列出当前定义的名字。
>>> a = [1, 2, 3, 4, 5]
>>> import fibo, sys
>>> fib = fibo.fib
>>> dir()
[__name__, a, fib, fibo, sys]注意dir()列出了所有各类名字:变量名、模块名、函数名,等等。dir()不会列出内置函数、变量的名字。要想列出内置名字的话需要使用标准模块__builtin__:
>>> import __builtin__
>>> dir(__builtin__)
[AccessError, AttributeError, ConflictError, EOFError, IOError,
ImportError, IndexError, KeyError, KeyboardInterrupt,
MemoryError, NameError, None, OverflowError, RuntimeError,
SyntaxError, SystemError, SystemExit, TypeError, ValueError,
ZeroDivisionError, __name__, abs, apply, chr, cmp, coerce,
compile, dir, divmod, eval, execfile, filter, float,
getattr, hasattr, hash, hex, id, input, int, len, long,
map, max, min, oct, open, ord, pow, range, raw_input,
reduce, reload, repr, round, setattr, str, type, xrange]6.4 包
Python中可以用“包”来组织Python的模块名字空间,名字引用时可以用“带点的模块名。例如,模块名A
补充:Web开发 , Python ,