可爱的Python_模块篇.pdf
模块篇|257 模块篇PCS200 os(.stat;.path)258PCS201 cmd 264PCS202 chardet 267PCS203 epydoc 270PCS204 ConfigParser 274PCS205 内建函式(enumerate)277PCS206 thread 280PCS207 threading 282PCS208 dict4ini 285PCS209 fnmatch 288PCS210 pickle 290PCS211 base64 294PCS212 shutil 298PCS213 time 304PCS214 ElementTree 309PCS215 random 312PCS216 socket 315PCS217 Tkinter 319258|Python学习作弊条PCS200 os(.stat;.path)概述os.path 是一个与平台无关的文件路径处理模块。它可以帮助我们解决在程序处理中碰到的一些复杂的路径处理问题,如“/”、“”、“”、“.”等路径分隔符处理不全面的问题,跨平台问题和组合一个可用的跨平台的路径地址问题。我们用简单的字符串拆分这些路径处理问题是很困难或者无法完成的,但是os.path都替你做好了解决方案,你只须使用它里面的函式就可以了。应用os.path.split os.path.split 的函式功能:os拆分路径,返回一个tuple,第一个元素是文件所在路径,第二个元素是对应文件名。如下面的一个小测试:1 import os.path 2 3 for path in /one/two/three,4 /one/two/three/,5 /,模块篇|259 6 .,7 :8 print%s:%s%(path,os.path.split(path)对于一个文件(具有绝对路径或相对路径),使用 os.path.split()可以将其拆成对应路径名(不以路径分割符(如/结尾)和文件名;对于一个路径,则返回该路径(同样,不以路径分割符,(如/结尾),而对应的文件名为空。这里比较奇特的是对于当前文件夹(.),os.path.split()把它看作是文件名。$python pcs-200-1.py /one/two/three:(/one/two,three)/one/two/three/:(/one/two/three,)/:(/,).:(,.):(,)os.path.basename os.path.basename 的函式功能:只获取某路径对应的文件名。修改上面的例子:1 import os.path 2 3 for path in /one/two/three,4 /one/two/three/,5 /,6 .,7 :8 print%s:%s%(path,os.path.basename(path)如果这里的函式参数只是一个路径,不是文件名,则返回对应的文件名为空。同样对于.也比较奇怪。$python pcs-200-2.py /one/two/three:three/one/two/three/:/:.:.:260|Python学习作弊条os.path.dirname os.path.dirname的函式功能:只获取某路径对应的路径,不含文件名。再修改之前的例子:1 import os.path 2 3 for path in /one/two/three,4 /one/two/three/,5 /,6 .,7 :8 print%s:%s%(path,os.path.dirname(path)同样,返回的路径名是不以路径分割符(如/)结尾的。$python pcs-200-3.py /one/two/three:/one/two/one/two/three/:/one/two/three/:/.:os.path.splitext os.path.splitext的函式功能:将路径、文件名、扩展名分开,并以一个tuple 的形式返回。1 import os.path 2 3 for path in filename.txt,filename,/path/to/filename.txt,/,:4 print%s:%path,os.path.splitext(path)可以看到 os.path.splittext 只是很单纯地将文件名和扩展名分开了,如下所示。$python pcs-200-4.py filename.txt:(filename,.txt)filename:(filename,)/path/to/filename.txt:(/path/to/filename,.txt)/:(/,):(,)模块篇|261 monprefix monprefix 的函式功能:看一个比较cool 的功能就是要在一组路径中,找到一个共同的前缀,比如:1 import os.path 2 3 paths=/one/two/three/four,4 /one/two/threefold,5 /one/two/three/,6 7 print paths 8 print monprefix(paths)$python pcs-200-5.py /one/two/three/four,/one/two/threefold,/one/two/three/one/two/three os.path.join os.path.join 的函式功能:使用os.path.join 组合一些零散的字符串,生成一个安全的路径表示,如下所示。1 import os.path 2 3 for parts in (one,two,three),4 (/,one,two,three),5 (/one,/two,/three),6 :7 print parts,:,os.path.join(*parts)也就是将一系列短路径拼合成有效的长路径。$python pcs-200-6.py (one,two,three):one/two/three(/,one,two,three):/one/two/three(/one,/two,/three):/three os.path.expanduser os.path.expanduser的函式功能:可以利用 os.path.expanduser 寻找用户的 home 目录,如下262|Python学习作弊条所示。1 import os.path 2 3 for user in ,root,mysql:4 lookup=+user 5 print lookup,:,os.path.expanduser(lookup)user是表示某个用户的home目录,表示当前用户的home目录。$python pcs-200-7.py :/home/shengyan root:/root mysql:/var/lib/mysql os.path.expandvars os.path.expandvars的函式功能:使用 os.path.expandvars来读取路径中系统环境变量的值。在下面的示例中,先使用os.environ 增加定义了一个环境变量MYVAR,并为其赋值VALUE,然后使用 os.path.expandvars将出现在路径中的环境变量扩展为对应值。1 import os.path 2 import os 3 4 os.environMYVAR=VALUE 5 6 print os.path.expandvars(/path/to/$MYVAR)$python pcs-200-8.py /path/to/VALUE os.path.normpath os.path.normpath的函式功能:处理不规则路径字符串,将其转化为正常的路径。比如:1 import os.path 2 3 for path in one/two/three,4 one/./two/./three,5 one/./one/two/three,6 :7 print path,:,os.path.normpath(path)模块篇|263$python pcs-200-9.py one/two/three:one/two/three one/./two/./three:one/two/three one/./one/two/three:one/two/three os.path.abspath os.path.abspath的函式功能:将相对路径转换为绝对路径,如下所示。1 import os.path 2 3 for path in .,.,./one/two/three,./one/two/three:4 print%s:%s%(path,os.path.abspath(path)$python pcs-200-10.py .:/home/shengyan/LovelyPython/PCS/pcs-200.:/home/shengyan/LovelyPython/PCS./one/two/three:/home/shengyan/LovelyPython/PCS/pcs-200/one/two/three./one/two/three:/home/shengyan/LovelyPython/PCS/one/two/three 问题要注意在两个根目录做join 操作时经常出现的问题,如下所示:1 import os 2 print os.path.join(/tmp,/var)执行结果为:/var 从结果中可以看到,并不是将两个路径做了简单连接,通过看help(os.path.join)可以看到,路径的拼接是从/开始的,所以会以“后一个开始/”为初始路径,要特别注意。探讨如果不使用 os.path这个模块,而是自己手工处理以上的例子,可以试试看需要如何处理,会遇到哪些困难。264|Python学习作弊条PCS201 cmd 概述cmd 模块为命令行接口(command-line interfaces,CLI)提供了一个简单的框架。它经常被用在 pdb(Python 调试模块)模块中,当然也可以在自己的程序中使用它来创建命令行程序。应用下面先举个 cmd 模块使用的小例子:1#-*-coding:utf-8-*-2 import cmd 3 import string,sys 4 5 class CLI(cmd.Cmd):6 7 def _init_(self):8 cmd.Cmd._init_(self)9 self.prompt=#定义命令行提示符10 11 def do_hello(self,arg):#定义 hello命令所执行的操作12 print hello again,arg,!13 14 def help_hello(self):#定义 hello命令的帮助输出模块篇|265 15 print syntax:hello message,16 print-prints a hello message 17 18 def do_quit(self,arg):#定义 quit命令所执行的操作19 sys.exit(1)20 21 def help_quit(self):#定义 quit命令的帮助输出22 print syntax:quit,23 print-terminates the application 24 25#定义 quit的快捷方式26 do_q=do_quit 27 28#创建 CLI实例并运行29 cli=CLI()30 cli.cmdloop()从这个例子可以看出,首先 CLI 类继承了 cmd.Cmd 类,然后在类中定义了两条命令hello和 quit,而命令q 被作为quit 的短命令形式。也就是说,若须另外定义一条命令,如command,只要在CLI 类中增加一个do_command 函式,而该命令对应的帮助信息由help_command函式给出。使用cmd.Cmd类编写命令行处理程序是非常容易的。运行上述例子,可以进入如下的命令行:$python pcs-201.py?Documented commands(type help):=hello quit Undocumented commands:=help q help hello syntax:hello message-prints a hello message hello LovelyPython hello again LovelyPython!find*Unknown syntax:find q 266|Python学习作弊条就像示例中所写的那样,自定义的 CLI 类提供了hello和quit命令,可以正常使用它们,而find命令是没有定义的,所以命令行提示为未知语法。最后的q 命令和 quit 是一样的功能,即退出程序。小结使用 cmd 模块可以方便编写命令行程序,同时使用getopt 和 optparse这两个模块可以很方便地解析命令行参数。这里向读者推荐一个比cmd 更好的模块,是由Doug Hellmann编写的命令行处理类CommandLineApp,具体可以访问以下网站:CommandLineApp 描述:http:/ 相关代码:http:/ PCS202 chardet 概述chardet是一个开源的字符编码自动检测模块,是基于 Python 实现的。读者可以在 chardet的网站上下载这个模块并根据源码包中的相关说明进行安装。chardet模块下载:http:/chardet.feedparser.org/download/chardet-1.0.1.tgz 精巧地址:http:/bit.ly/8EXnf 应用检测字符编码利用 chardet 来自动检测字符编码的最简单方式是使用dectect(),它以一个非unicode 字符串作为参数,返回一个由被检测字符串的编码方式及其可信度数值(介于01 之间)组成的字典数据结构。下面的例子中,首先使用urllib.urlopen方法打开百度首页,并读取其内容作为被检测数据,然后使用chardet.detect检测并返回结果:import urllib rawdata=urllib.urlopen(http:/).read()import chardet chardet.detect(rawdata)confidence:0.98999999999999999,encoding:GB2312 268|Python学习作弊条可以看到,检测出该网页编码方式GB2312 的可信度是 0.98999999999999999,一个非常高的值。渐进检测字符编码对于大量的文本,chardet 提供了可以渐进检测字符编码的相关方法,并且在满足可信度后会自动停止检测。具体是通过UniversalDetector 类的 feed 方法不断检测每个文本块,当达到最小可信度阈值时,就标记 UniversalDetector 类的 done 值为 True,表示完成检测。已经读取完待检测文本之后若调用UniversalDetector 类的 close方法,它会在没有达到最小可信度的情况下再做一些计算,以便返回最大程度上准确的值,该值和chardet.detect函式是一样的字典结构。下面是一个例子:1 import urllib 2 from chardet.universaldetector import UniversalDetector 3 4 usock=urllib.urlopen(http:/)5 detector=UniversalDetector()6 for line in usock.readlines():7 detector.feed(line)8 if detector.done:break 9 detector.close()10 usock.close()11 print detector.result 这个例子同样先打开百度首页,接着创建了一个UniversalDetector 对象 detector,在接下来的 for 循环中,读取数据的同时检测该数据,当 done 值为 True 时表示检测完成退出for循环,最后关闭数据流并打印结果:$python pcs-202-1.py confidence:0.98999999999999999,encoding:GB2312 如果想对多个独立文本进行编码检测,可以重复使用同一个UniversalDetector 对象,只要在每个文本开始检测前调用reset(),以表明接下来读取的是与之前文本相独立的字符串,然后就可以在类似上述例子中调用feed(),最后调用close()结束,最终的检测结果放在result 中,如下所示。1 import glob 2 from chardet.universaldetector import UniversalDetector 3 模块篇|269 4 detector=UniversalDetector()5 for filename in glob.glob(*.py):6 print filename.ljust(60),7 detector.reset()8 for line in file(filename,rb):9 detector.feed(line)10 if detector.done:break 11 detector.close()12 print detector.result 其运行结果如下:$python pcs-202-2.py pcs-202-1.py confidence:1.0,encoding:ascii pcs-202-2.py confidence:1.0,encoding:ascii 270|Python学习作弊条PCS203 epydoc 概述epydoc 是专门用于从源码注释中生成各种格式(如Html、plaintext、LaTeX 和 PDF)文档的工具。它支持多种文档化标签语法:Epytext(轻量级的标记语言,用于标记各种文档 字 符 串,主 要 是 在 一 些 特 定 的 标 签 上 添 加 相 关 的 信 息,例 如 参 数 类 型 等)、ReStructuredText(一种易用的,所见即所得的文本标签语法)、Javadoc(用于 Java 源代码的文档化标记语言)以及普通文本。应用安装这里先介绍源码安装的步骤:$wget http:/ zxvf epydoc-3.0.1.tar.gz#解压文件$cd epydoc-3.0.1/#进入目标目录/epydoc-3.0.1$sudo python setup.py install#安装,需要root权限sudo password for shengyan:running install running build running build_py 模块篇|271.#完毕其他平台下的更多安装方法可参见安装手册:http:/ epydoc 生成文档,得先在源代码中插入相关的各种格式的Docstring,它支持多种标签。Epydoc 支持标签的详细介绍请看:http:/ author:.作者 license:.版权 contact:.联系2.py状态信息 version:.版本推荐使用$Id$todo ver:.改进,可以指定针对的版本3.py模块信息 var v:.模块变量v 说明 type v:.模块变量类型v 说明4.py函式信息 param p:.参数 p 说明 type v:.参数 p 类型说明 return:.返回值说明 rtype v:.返回值类型说明5.py提醒信息 note:.注解 attention:.注意 bug:.问题 warning:.警告6.py关联信息 see:.参考资料272|Python学习作弊条epydoc 支持三种标签的语法。Epytext tag:内容.ReStructuredText :tag:内容.Javadoc tag 内容.更多的 Tag语法及注释规范可参见文档化开发注释规范:http:/ docstring 生成 html 文档1#coding:utf-8 2 def MyFunc():3 4 docstring文档5 用 epydoc来生成我6 7 pass 运行 epydoc来生成文档:$epydoc pcs-203-1.py 在当前目录下会生成一个html 文件夹,点击index.html,即可看到生成的文档结果(如图 PCS203-1所示):图 PCS203-1 模块篇|273 问题还可以通过书写一个简单的配置文件,生成更丰富的文档。如:#可以命名为epydoc.cfg epydoc#项目信息,名称及URL name:Backup url:http:/ target:apidocs/#指定图形生成工具,这样就可以产生各种UML 图graph:all dotpath:/usr/bin/dot 然后使用如下命令即可生成所需文档:$epydoc-config epydoc.cfg#获得最新的 API文档274|Python学习作弊条PCS204 ConfigParser 概述ConfigParser是用来处理 ini 格式的配置文件的Python 标准库。为自己的程序建立一个可配置的文件是一个良好的习惯,可以不修改源代码,就能动态地改变程序的运行结果,方便维护。应用read(self,filenames)read(self,filenames)的函式功能:直接读取ini 文件内容,filenames 可以是一文件名或是文件名列表。示例如下:from ConfigParser import ConfigParser config=ConfigParser()config.read(approachrc)approachrc 模块篇|275 sections(self)sections(self)的函式功能:得到所有的section,并以列表的形式返回。示例如下:config.sections()portal options(self,section)options(self,section)的函式功能:得到指定section的所有 option。示例如下:config.options(portal)username,host,url,password,port get(self,section,option,raw=False,vars=None)get(self,section,option,raw=False,vars=None)的函式功能:得到 section中 option 的值,返回为 string 类型。示例如下:config.get(portal,username)dhellmann set(self,section,option,value)set(self,section,option,value)的函式功能:对 section 中的 option 进行设置,其值为value。示例如下:config.set(portal,username,lovelypython)config.get(portal,username)lovelypython 实例假设有如下的配置文件示例:portal url=http:/%(host)s:%(port)s/Portal 276|Python学习作弊条username=dhellmann host=localhost password=SECRET port=8080 使用 ConfigParse进行解析:1 from ConfigParser import ConfigParser 2 import os 3 4 filename=os.path.join(.,approachrc)5 print filename 6 7 config=ConfigParser()8 config.read(filename)9 10 url=config.get(portal,url)11 print url 这段代码中,config 读取 approachrc 内容,获得字段portal 中选项 url 的值,可以看到approachrc中的 url 为 http:/%(host)s:%(port)s/Portal,这里的%(host)s和%(port)s 又分别读取了 host和 port 的值,最终得到了如下的结果:$python pcs-204-1.py ./approachrc http:/localhost:8080/Portal 模块篇|277 PCS205 内建函式(enumerate)概述Python 除了有语言简洁,容易上手等优点,还有一个重要的优点,就是存在大量的内置函式,方便编程。本将介绍这些常用函式,让我们更好地了解Python 的诱人之处。应用enumerate enumerate是 Python 2.3 中新增的内置函式,它的英文说明为:enumerate(iterable)Return an enumerate object.iterable must be a sequence,an iterator,or some other object which supports iteration.The next()method of the iterator returned by enumerate()returns a tuple containing a count(from zero)and the corresponding value obtained from iterating over iterable.enumerate()is useful for obtaining an indexed series:(0,seq0),(1,seq1),(2,seq2),.New in version 2.3.它特别适合用于for 循环,当我们同时需要序号和元素时可以使用这个函式。比如,有一个字符串数组,需要一行一行打印出来,同时每行前面加上序号,从1 开始,如下所示:278|Python学习作弊条1 mylist=a,b,c 2 for index,obj in enumerate(mylist):3 print index,obj 输出结果为:0 a 1 b 2 c map 函式说明:map(function,sequence,sequence,.)-list,这两个参数中一个是函式名,另一个是列表或元组,它会返回一个列表。比如,将数组中每一个数乘以2:1 print map(lambda x:x*2,1,2,3,4,5)-,map(lambda x:x*2,1,2,3,4,5)输出结果为:map(lambda x:x*2,1,2,3,4,5)-2,4,6,8,10 zip 函式说明:zip(seq1,seq2.)-(seq10,seq20.),(.),这个函式可以同时循环两个一样长的数组,返回一个包含每个参数元组对应元素的元组。各参数元组长度最好一致,若不一致,采取截断方式,使得返回的结果元组的长度为各参数元组长度最小值。比如:1 print zip(1,2,3,4,5,6):2 for x,y in zip(1,2,3,4,5,6):3 print x,y,x,y 输出结果为:zip(1,2,3,4,5,6):x,y 1 4 x,y 2 5 x,y 3 6 filter 函式说明:filter(function or None,sequence)-list,tuple,or string,它包括两个参数,分别是 function 和 list。该函式根据function 参数返回的结果是否为真来过滤list 参数中的项,模块篇|279 最后返回一个新列表。比如,过滤掉数组中小于3 的数:1 print filter(lambda x:x3,1,2,3,4,5)-,filter(lambda x:x3,1,2,3,4,5)输出结果为:filter(lambda x:x3,1,2,3,4,5)-4,5 dir 函式说明:它用于列出一个变量的所有方法和属性。动态语言经常遇到的问题就是,当前的变量究竟有哪些可用的方法和属性?通过dir()函式就可以很容易地解决了,如下所示:1 s=Hello Python 2 print dir(s)运行结果:_add_,_class_,_contains_,_delattr_,_doc_,_eq_,_ge_,_getattribute_,_getitem_,_getnewargs_,_getslice_,_gt_,_hash_,_init_,_le_,_len_,_lt_,_mod_,_mul_,_ne_,_new_,_reduce_,_reduce_ex_,_repr_,_rmod_,_rmul_,_setattr_,_str_,capitalize,center,count,decode,encode,endswith,expandtabs,find,index,isalnum,isalpha,isdigit,islower,isspace,istitle,isupper,join,ljust,lower,lstrip,partition,replace,rfind,rindex,rjust,rpartition,rsplit,rstrip,split,splitlines,startswith,strip,swapcase,title,translate,upper,zfill 280|Python学习作弊条PCS206 thread 概述Python 是支持多线程的,并且是native的线程,主要是通过thread和 threading 这两个模块来实现的。thread是比较底层的模块,threading 是 thread的包装,可以更加方便地被使用。这里需要提一下的是Python 对线程的支持还不够完善,不能利用多CPU,但是下个版本的 Python 中已经考虑改进这点。我们不建议使用thread模块,是由于以下几点原因:首先,更高级别的threading 模块更为先进,对线程的支持更为完善,而且使用thread 模块里的属性有可能会与threading 冲突。其次,低级别 thread模块的同步原语很少(实际上只有一个),而 threading模块则有很多。还有一个不要使用thread 的原因,就是它对你的进程什么时候应该结束完全没有控制,当主线程结束时,所有的线程都会被强制结束掉,没有警告,也不会有正常的清除工作。应用下面举个使用 thread 模块的简单例子:1#!/usr/bin/env python 2#-*-coding:utf-8-*-3 4 import thread 5 from time import sleep,ctime 6 模块篇|281 7 def loop0():8 print start loop 0 at:,ctime()9 sleep(4)10 print loop 0 done at:,ctime()11 12 def loop1():13 print start loop 1 at:,ctime()14 sleep(2)15 print loop 1 done at:,ctime()16 17 def main():18 print starting at:,ctime()19#创建一个新线程,执行loop0 20 thread.start_new_thread(loop0,()21#创建另一个新线程,执行loop1 22 thread.start_new_thread(loop1,()23 sleep(6)24 print all DONE at:,ctime()25 26 if _name_=_main_:27 main()在这个例子中,主程序创建了两个线程后进入睡眠6 秒,而两个线程分别执行loop0 和loop1,线程 0 在 loop0 中睡眠了 4 秒,而线程 1 在 loop1 中只睡眠了 2 秒,这样导致线程1 先结束,线程0后结束,最后主程序6 秒后退出。运行之后,可以看到如下结果:$python pcs-206-1.py starting at:Sun Aug 31 20:04:44 2008 start loop 0 at:Sun Aug 31 20:04:44 2008 start loop 1 at:Sun Aug 31 20:04:44 2008 loop 1 done at:Sun Aug 31 20:04:46 2008 loop 0 done at:Sun Aug 31 20:04:48 2008 all DONE at:Sun Aug 31 20:04:50 2008 282|Python学习作弊条PCS207 threading 概述Python 是支持多线程的,并且是native的线程,主要是通过thread和 threading 这两个模块来实现的。thread是比较底层的模块,threading 是 thread的包装,可以更加方便地被使用。这里需要提一下的是Python 对线程的支持还不够完善,不能利用多CPU,但是下个版本的 Python 中已经考虑改进这点。应用threading 模块主要功能是让一些线程的操作对象化了,创建了叫Thread的类。使用线程有两种方法,一种是创建线程要执行的函式,把这个函式传递进Thread对象里,让它来执行,如下所示。1#-*-coding:utf-8-*-2 import string,threading,time 3 4 def thread_main(a):5 global count,mutex 6#获得线程名 7 threadname=threading.currentThread().getName()8 9 for x in xrange(0,int(a):10#取得锁11 mutex.acquire()12 count=count+1 13#释放锁模块篇|283 14 mutex.release()15 print threadname,x,count 16 time.sleep(1)17 18 def main(num):19 global count,mutex 20 threads=21 22 count=1 23#创建一个锁24 mutex=threading.Lock()25#先创建线程对象26 for x in xrange(0,num):27 threads.append(threading.Thread(target=thread_main,args=(10,)28#启动所有线程29 for t in threads:30 t.start()31#主线程中等待所有子线程退出32 for t in threads:33 t.join()34 if _name_=_main_:35 num=4 36#创建 4 个线程37 main(4)在这个例子中,主程序创建了4 个线程,每个线程对全局变量count 进行加 1 运算。因为多个线程对同一个变量进行了加1 操作,为了避免冲突,在修改变量 count 之前加锁,之后解锁释放。运行后,可以看到:$python pcs-207-1.py Thread-1 0 2 Thread-2 0 3 Thread-3 0 4 Thread-4 0 5 Thread-1 1 6.Thread-1 8 34 Thread-2 8 35 Thread-3 8 36 Thread-4 8 37 Thread-1 9 38 Thread-2 9 39 Thread-3 9 40 Threa