荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: georgehill (清风浮云 人生), 信区: Linux
标  题: PYTHON教程 第六章 模块(转寄)
发信站: BBS 荔园晨风站 (Thu Oct 19 17:43:55 2000), 站内信件

【 以下文字转载自 georgehill 的信箱 】
【 原文由 georgehill.bbs@melon.gznet.edu.cn 所发表 】
发信人: nic (心只有美!), 信区: Linux
标  题: PYTHON教程 第六章 模块(转寄)
发信站: 华南网木棉站 (Thu Oct 19 17:23:55 2000), 站内信件

【 以下文字转载自 nic 的信箱 】
发信人: chenhao (答辩结束,开写论文), 信区: Linux
标  题: PYTHON教程 第六章 模块(转寄)
发信站: 北大未名 (Tue Jun 20 18:00:57 2000), 站内信件

【此篇文章是由自动发信系统所张贴】

发信人: yyh (一笑了之), 信区: Linux
标  题: PYTHON教程 第六章 模块(转寄)
发信站: BBS 水木清华站 (Tue Jun 20 17:05:23 2000)

第六章 模块
如果退出Python解释程序然后再进入,原有的定义(函数和变量)就丢失了。所以,如
果需要写长一点的程序,最好用一个文本编辑程序为解释程序准备输入,然后以程序文
件作为输入来运行Python解释程序,这称为准备脚本(script)。当你的程序变长时,
最好把它拆分成几个文件以利于维护。你还可能想在几个程序中都使用某个很方便的函
数,但又不想把函数定义赋值到每一个程序中。
为了支持这些,Python有一种办法可以把定义放在一个文件中然后就可以在一个脚本中
或交互运行中调用。这样的文件叫做一个模块;模块中的定义可以导入其它模块或主模
块(主模块指在解释程序顶级执行的脚本或交互执行的程序所能访问的变量集合)。
模块是包含了Python定义和语句的文件。文件名由模块名加上后缀“.py”构成。在模块
内,模块的名字(作为一个字符串)可以由全局变量__name__的值获知。例如,在Pyth
on的搜索路径中用你习惯使用的文本编辑器(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 377
6.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文件
为了提高调用许多标准模块的小程序的启动时间,一个重要的措施是,如果在找到“sp
am.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”读入的运行更快,它们只是调入速
度更快一些。
如果一个程序是用在命令行指定脚本文件名的方式运行的,脚本的字节码不会写入“.p
yc ”或“.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.B代表包“A”内名为“B”的子模块。正如使用模块可以使不同模块
的作者不用顾虑彼此的全局变量名会冲突,使用带点的模块名可以使多模块包如NumPy和
PIL的作者不需要担心彼此的模块名会冲突。
假设你有一系列处理声音文件和声音数据的模块(称为一个“包”)。有许多种不同的
声音文件格式(通常用扩展名来识别,如“wav”,“.aiff”,“.au”),所以你可能
需要制作并维护一组不断增加的模块来处理不同文件格式的转换。你还可能需要对声音
数据进行许多不同的操作(如混音、回响、均衡、产生模拟立体声效果),所以你还需
要不断增加模块来执行这些操作。一下是你的程序包的可能的结构(用一个分层文件系
统表示):

Sound/                          顶层包
      __init__.py               初始化音响包
      Formats/                  用于文件格式转换的子程序包
              __init__.py
              wavread.py
              wavwrite.py
              aiffread.py
              aiffwrite.py
              auread.py
              auwrite.py
              ...
      Effects/                  用于音响效果的子程序包
              __init__.py
              echo.py
              surround.py
              reverse.py
              ...
      Filters/                  用于滤波的子程序包
              __init__.py
              equalizer.py
              vocoder.py
              karaoke.py
              ...

包目录中的“__init__.py”文件是必须得,用来指示Python把这个目录看成包,这可以
防止有相同名字如“string”的子目录掩盖住在搜索路径后面一些出现的模块定义。在
最简单的情况下,“__init__.py”可以是一个空文件,它也可以包含初始化包所需的代
码,和设置“__all__”变量,这些后面会加以讨论。
包的用户可以从包中导入单独的模块,如:
    import Sound.Effects.echo
这可以把子模块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直接可用:
echofilter(input, output, delay=0.7, atten=4)
注意使用“from 包 import 项”这样的格式时,导入的项可以是包的一个子模块(或子
包),也可以是包内定义的其它名字如函数、类、变量。导入语句首先查找包内是否定
义了所需的项,如果没有则假设它是一个模块然后调入。如果找不到,结果引起Import
Error。
相反的,当使用“import item.subitem.subsubitem”这样的格式时,除最后一个外其
它各项都应该是包,最后一项可以是包也可以是模块,不允许是前面一项内部定义的类
、函数或变量。
6.4.1 从包中导入*
现在,如果用户写“from Sound.Effects import *”会发生什么情况?理想情况下我们
希望这应该扫描文件系统,找到所有包内的子模块并把它们都导入进来。不幸的是这种
操作在Mac和Windows平台上不能准确实现,这两种操作系统对文件名的大小写没有准确
信息。在这些平台上,不知道名为“ECHO.PY”的文件会作为模块echo、Echo还是ECHO被
导入。(例如,Windows 95在显示文件名时总是讨厌地把第一个字母大写)。DOS的8+
3文件名限制更是对长模块名造成了有趣的困难。
这个问题的唯一解决办法是由模块作者显式地提供包的索引。引入*的import语句遵循如
下规定:如果包的“__init__.py”文件定义了一个名为“__all__”的列表,这个列表
就作为从包内导入*时要导入的所有模块的名字表。因此当包的新版本发布时需要包的作
者确保这个列表是最新的。包的作者如果认为不需要导入*的话也可以不支持这种用法。
例如,文件Sounds/Effects/__init__.py 可以包含如下代码:

__all__ = ["echo", "surround", "reverse"]
这意味着from Sound.Effects import *将从Sound包中导入指定的三个子包。
如果没有定义__all__,则from Sound.Effects import *语句不会导入Sound.Effects包
中的所有子模块;此语句只能保证Sound.Effects被导入(可能是执行其初始化代码“_
_init__.py ”)并导入包中直接定义的名字。这包括由“__init__.py”定义的任何名
字和显式导入的子模块名。这也包括模块中已经在前面用import显式地导入的子模块,
例如:

import Sound.Effects.echo
import Sound.Effects.surround
from Sound.Effects import *

在这个例子中,echo和surround模块被导入当前名字空间,因为它们在执行from...imp
ort 语句时已定义(在定义了__all__的情况下这一点也是成立的)。
注意用户应尽量避免使用从模块或包中导入*的做法,因为这样经常导致可读性差的代码
。尽管如此,在交互运行时可以用导入*的办法节省敲键次数,而且有些模块在设计时就
考虑到了这个问题,它们只输出遵循某种约定的名字。注意,from 包 import 特定子模
块的用法并没有错,实际上这还是我们推荐的用法,除非程序还需要用到来自其它包的
同名的子模块。
6.4.2 包内部引用
子模块常常需要彼此引用。例如,模块surround可能要用到模块echo。事实上,这样的
引用十分常见,所以import语句首先从子模块的所在包中寻找要导入的子模块才在标准
模块搜索路径查找。所以,模块surround只要写import echo或from echo import echo
filter。如果在包含本模块的包中没有找到要导入的模块,import语句将去寻找指定名
字的顶级模块。
当包组织成子包时(比如例中的Sound包),没有一种简单的办法可以引用兄弟包中的子
模块――必须使用子模块的全名。例如,如果模块Sound.Filters.vocoder要引用Sound
.Effects 包中的echo模块,它可以用Sound.Effects import echo。

--
※ 来源:·BBS 水木清华站 smth.org·[FROM: 162.105.17.22]
※ 来源:·BBS 水木清华站 smth.org·[FROM: 162.105.17.22]
--
※ 转载:·北大未名 BBS.PKU.EDU.CN·[FROM: 202.38.126.48]
--
※ 转寄:·北大未名站 bbs.pku.edu.cn·[FROM: 202.38.248.201]
--
※ 转载:.华南网木棉站 bbs.gznet.edu.cn.[FROM: 202.38.248.201]
--
※ 转寄:.华南网木棉站 bbs.gznet.edu.cn.[FROM: 深大荔园晨风转站]
--
※ 转载:·BBS 荔园晨风站 bbs.szu.edu.cn·[FROM: 192.168.1.115]
※ 修改:·jjksam 於 Mar  1 12:09:41 修改本文·[FROM: 192.168.0.146]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店