今天学习第一模块的最后一课课程--函数:
python的第一个函数:
1 1 def func1():1
2 2 print('第一个函数')
3 3 return 0
4 4 func1()
同时返回多种类型时,将是返回一元组:
1 1 def func2():2
2 2 return 1,"二",[3,'4'],{'五':'六','七':8}#返回多种数据类型
3 3 data=func2()
4 4 print(data)
函数参数的调用:
1,位置调用:编写时需要一一对应,如果少了,或是多少都会出错!
1 1 def func3(x,y):3
2 2 z=x+y
3 3 return z
4 4
5 5 print(func3(1,2,3))#参数不对,报错
2,关键字调用:
1 1 def func3(x,y):4
2 2 print(x)
3 3 print(y)
4 4 z=x+y
5 5 return z
6 6
7 7 func3(y=1,x=2)#可以不对应位置
3,位置调用与关键字调用可以同时使用,但是需要注意的问题:
1 1 def func4(x,y,z):5
2 2 print(x)
3 3 print(y)
4 4 print(z)
5 5 return 0
6 6
7 7 func4(1,z=3,y=4)#正确的调用
8 8 func4(x=1,3,z=3)#错误的调用
参数组:
使用参数组可以传值列表,字典:格式
1 1 def func5(x,*args,**kwargs):View Code
2 2 print(x)
3 3 print(*args)
4 4 print(**kwargs)
5 5
6 7 func5(3,4,name='3',age='5')#字典 列表 同时传参
7 8 func5(3,1,3,4)#列表参数
8 9 #列表参数是特殊的位置参数,可以不传值, 字典是特殊的关键字参数
全局变量与局部变量的作用域:
1 1 def func6():View Code
2 2 name='工'
3 3 print(name)
4 4 def func7():
5 5 print(name)#全局变量在全局产生作用
6 6 global name
7 7 name='一'
8 8 func6()##局部变量只在函数中起作用 并且,全局变量与当前的局部相同时局部变量生效
9 9 func7()#全局变量在全局产生作用
10 10 print(name)
1 1 def func8(name,n):View Code
2 2 print(list)
3 3 num=5##在子程序进行修改
4 4 str1='ttt'##在子程序进行修改
5 5 list2[n]=888#在子程序进行修改
6 6 list[name]='xxoo'#在子程序可以进行修改
7 7 print('函数中输出',list,num,str1,list2)
8 8
9 9 #当全局变量为整数和字符串时不能被修改,为列表,字典可以被修改
10 10 global list,num,str1 #定义全局变量
11 11 num=3
12 12 str1='dg'
13 13 list={"name":"kkkk",'age':34}
14 14 list2=[1,2.4,6]
15 15 func8("name",1)
16 16 print('全局输出',list,num,str1,list2)#全局列表,字典被修改,整数与字符串不能被修改
哈哈,明天开始作业啦!作业好难感觉!
1 默认标准库位置(安装位置不同请自己更换)Python3标准库中文翻译
2
3 C:\Users\Administrator\AppData\Local\Programs\Python\Python36-32\Lib
4
5 文本
6 1. string:通用字符串操作
7 2. re:正则表达式操作
8 3. difflib:差异计算工具
9 4. textwrap:文本填充
10 5. unicodedata:Unicode字符数据库
11 6. stringprep:互联网字符串准备工具
12 7. readline:GNU按行读取接口
13 8. rlcompleter:GNU按行读取的实现函数
14
15 二进制数据
16 9. struct:将字节解析为打包的二进制数据
17 10. codecs:注册表与基类的编解码器
18
19 数据类型
20 11. datetime:基于日期与时间工具
21 12. calendar:通用月份函数
22 13. collections:容器数据类型
23 14. collections.abc:容器虚基类
24 15. heapq:堆队列算法
25 16. bisect:数组二分算法
26 17. array:高效数值数组
27 18. weakref:弱引用
28 19. types:内置类型的动态创建与命名
29 20. copy:浅拷贝与深拷贝
30 21. pprint:格式化输出
31 22. reprlib:交替repr()的实现
32
33 数学
34 23. numbers:数值的虚基类
35 24. math:数学函数
36 25. cmath:复数的数学函数
37 26. decimal:定点数与浮点数计算
38 27. fractions:有理数
39 28. random:生成伪随机数
40
41 函数式编程
42 29. itertools:为高效循环生成迭代器
43 30. functools:可调用对象上的高阶函数与操作
44 31. operator:针对函数的标准操作
45
46 文件与目录
47 32. os.path:通用路径名控制
48 33. fileinput:从多输入流中遍历行
49 34. stat:解释stat()的结果
50 35. filecmp:文件与目录的比较函数
51 36. tempfile:生成临时文件与目录
52 37. glob:Unix风格路径名格式的扩展
53 38. fnmatch:Unix风格路径名格式的比对
54 39. linecache:文本行的随机存储
55 40. shutil:高级文件操作
56 41. macpath:Mac OS 9路径控制函数
57
58 持久化
59 42. pickle:Python对象序列化
60 43. copyreg:注册机对pickle的支持函数
61 44. shelve:Python对象持久化
62 45. marshal:内部Python对象序列化
63 46. dbm:Unix“数据库”接口
64 47. sqlite3:针对SQLite数据库的API 2.0
65
66 压缩
67 48. zlib:兼容gzip的压缩
68 49. gzip:对gzip文件的支持
69 50. bz2:对bzip2压缩的支持
70 51. lzma:使用LZMA算法的压缩
71 52. zipfile:操作ZIP存档
72 53. tarfile:读写tar存档文件
73
74 文件格式化
75 54. csv:读写CSV文件
76 55. configparser:配置文件解析器
77 56. netrc:netrc文件处理器
78 57. xdrlib:XDR数据编码与解码
79 58. plistlib:生成和解析Mac OS X .plist文件
80
81 加密
82 59. hashlib:安全散列与消息摘要
83 60. hmac:针对消息认证的键散列
84
85 操作系统工具
86 61. os:多方面的操作系统接口
87 62. io:流核心工具
88 63. time:时间的查询与转化
89 64. argparser:命令行选项、参数和子命令的解析器
90 65. optparser:命令行选项解析器
91 66. getopt:C风格的命令行选项解析器
92 67. logging:Python日志工具
93 68. logging.config:日志配置
94 69. logging.handlers:日志处理器
95 70. getpass:简易密码输入
96 71. curses:字符显示的终端处理
97 72. curses.textpad:curses程序的文本输入域
98 73. curses.ascii:ASCII字符集工具
99 74. curses.panel:curses的控件栈扩展
100 75. platform:访问底层平台认证数据
101 76. errno:标准错误记号
102 77. ctypes:Python外部函数库
103
104 并发
105 78. threading:基于线程的并行
106 79. multiprocessing:基于进程的并行
107 80. concurrent:并发包
108 81. concurrent.futures:启动并行任务
109 82. subprocess:子进程管理
110 83. sched:事件调度
111 84. queue:同步队列
112 85. select:等待I/O完成
113 86. dummy_threading:threading模块的替代(当_thread不可用时)
114 87. _thread:底层的线程API(threading基于其上)
115 88. _dummy_thread:_thread模块的替代(当_thread不可用时)
116
117 进程间通信
118 89. socket:底层网络接口
119 90. ssl:socket对象的TLS/SSL填充器
120 91. asyncore:异步套接字处理器
121 92. asynchat:异步套接字命令/响应处理器
122 93. signal:异步事务信号处理器
123 94. mmap:内存映射文件支持
124
125 互联网
126 95. email:邮件与MIME处理包
127 96. json:JSON编码与解码
128 97. mailcap:mailcap文件处理
129 98. mailbox:多种格式控制邮箱
130 99. mimetypes:文件名与MIME类型映射
131 100. base64:RFC 3548:Base16、Base32、Base64编码
132 101. binhex:binhex4文件编码与解码
133 102. binascii:二进制码与ASCII码间的转化
134 103. quopri:MIME quoted-printable数据的编码与解码
135 104. uu:uuencode文件的编码与解码
136
137 HTML与XML
138 105. html:HTML支持
139 106. html.parser:简单HTML与XHTML解析器
140 107. html.entities:HTML通用实体的定义
141 108. xml:XML处理模块
142 109. xml.etree.ElementTree:树形XML元素API
143 110. xml.dom:XML DOM API
144 111. xml.dom.minidom:XML DOM最小生成树
145 112. xml.dom.pulldom:构建部分DOM树的支持
146 113. xml.sax:SAX2解析的支持
147 114. xml.sax.handler:SAX处理器基类
148 115. xml.sax.saxutils:SAX工具
149 116. xml.sax.xmlreader:SAX解析器接口
150 117. xml.parsers.expat:运用Expat快速解析XML
151
152 互联网协议与支持
153 118. webbrowser:简易Web浏览器控制器
154 119. cgi:CGI支持
155 120. cgitb:CGI脚本反向追踪管理器
156 121. wsgiref:WSGI工具与引用实现
157 122. urllib:URL处理模块
158 123. urllib.request:打开URL连接的扩展库
159 124. urllib.response:urllib模块的响应类
160 125. urllib.parse:将URL解析成组件
161 126. urllib.error:urllib.request引发的异常类
162 127. urllib.robotparser:robots.txt的解析器
163 128. http:HTTP模块
164 129. http.client:HTTP协议客户端
165 130. ftplib:FTP协议客户端
166 131. poplib:POP协议客户端
167 132. imaplib:IMAP4协议客户端
168 133. nntplib:NNTP协议客户端
169 134. smtplib:SMTP协议客户端
170 135. smtpd:SMTP服务器
171 136. telnetlib:Telnet客户端
172 137. uuid:RFC4122的UUID对象
173 138. socketserver:网络服务器框架
174 139. http.server:HTTP服务器
175 140. http.cookies:HTTPCookie状态管理器
176 141. http.cookiejar:HTTP客户端的Cookie处理
177 142. xmlrpc:XML-RPC服务器和客户端模块
178 143. xmlrpc.client:XML-RPC客户端访问
179 144. xmlrpc.server:XML-RPC服务器基础
180 145. ipaddress:IPv4/IPv6控制库
181
182 多媒体
183 146. audioop:处理原始音频数据
184 147. aifc:读写AIFF和AIFC文件
185 148. sunau:读写Sun AU文件
186 149. wave:读写WAV文件
187 150. chunk:读取IFF大文件
188 151. colorsys:颜色系统间转化
189 152. imghdr:指定图像类型
190 153. sndhdr:指定声音文件类型
191 154. ossaudiodev:访问兼容OSS的音频设备
192
193 国际化
194 155. gettext:多语言的国际化服务
195 156. locale:国际化服务
196
197 编程框架
198 157. turtle:Turtle图形库
199 158. cmd:基于行的命令解释器支持
200 159. shlex:简单词典分析
201
202 Tk图形用户接口
203 160. tkinter:Tcl/Tk接口
204 161. tkinter.ttk:Tk主题控件
205 162. tkinter.tix:Tk扩展控件
206 163. tkinter.scrolledtext:滚轴文本控件
207
208 开发工具
209 164. pydoc:文档生成器和在线帮助系统
210 165. doctest:交互式Python示例
211 166. unittest:单元测试框架
212 167. unittest.mock:模拟对象库
213 168. test:Python回归测试包
214 169. test.support:Python测试工具套件
215 170. venv:虚拟环境搭建
216
217 调试
218 171. bdb:调试框架
219 172. faulthandler:Python反向追踪库
220 173. pdb:Python调试器
221 174. timeit:小段代码执行时间测算
222 175. trace:Python执行状态追踪
223
224 运行时
225 176. sys:系统相关的参数与函数
226 177. sysconfig:访问Python配置信息
227 178. builtins:内置对象
228 179. __main__:顶层脚本环境
229 180. warnings:警告控制
230 181. contextlib:with状态的上下文工具
231 182. abc:虚基类
232 183. atexit:出口处理器
233 184. traceback:打印或读取一条栈的反向追踪
234 185. __future__:未来状态定义
235 186. gc:垃圾回收接口
236 187. inspect:检查存活的对象
237 188. site:址相关的配置钩子(hook)
238 189. fpectl:浮点数异常控制
239 190. distutils:生成和安装Python模块
240
241 解释器
242 191. code:基类解释器
243 192. codeop:编译Python代码
244
245 导入模块
246 193. imp:访问import模块的内部
247 194. zipimport:从ZIP归档中导入模块
248 195. pkgutil:包扩展工具
249 196. modulefinder:通过脚本查找模块
250 197. runpy:定位并执行Python模块
251 198. importlib:import的一种实施
252
253 Python语言
254 199. parser:访问Python解析树
255 200. ast:抽象句法树
256 201. symtable:访问编译器符号表
257 202. symbol:Python解析树中的常量
258 203. token:Python解析树中的常量
259 204. keyword:Python关键字测试
260 205. tokenize:Python源文件分词
261 206. tabnany:模糊缩进检测
262 207. pyclbr:Python类浏览支持
263 208. py_compile:编译Python源文件
264 209. compileall:按字节编译Python库
265 210. dis:Python字节码的反汇编器
266 211. pickletools:序列化开发工具
267
268 其它
269 212. formatter:通用格式化输出
270
271 Windows相关
272 213. msilib:读写Windows Installer文件
273 214. msvcrt:MS VC++ Runtime的有用程序
274 215. winreg:Windows注册表访问
275 216. winsound:Windows声音播放接口
276
277 Unix相关
278 217. posix:最常用的POSIX调用
279 218. pwd:密码数据库
280 219. spwd:影子密码数据库
281 220. grp:组数据库
282 221. crypt:Unix密码验证
283 222. termios:POSIX风格的tty控制
284 223. tty:终端控制函数
285 224. pty:伪终端工具
286 225. fcntl:系统调用fcntl()和ioctl()
287 226. pipes:shell管道接口
288 227. resource:资源可用信息
289 228. nis:Sun的NIS的接口
290 229. syslog:Unix syslog程序库
1 1. 核心模块python标准库实例-1核心模块
2 o 1.1. 介绍
3 o 1.2. _ _builtin_ _ 模块
4 o 1.3. exceptions 模块
5 o 1.4. os 模块
6 o 1.5. os.path 模块
7 o 1.6. stat 模块
8 o 1.7. string 模块
9 o 1.8. re 模块
10 o 1.9. math 模块
11 o 1.10. cmath 模块
12 o 1.11. operator 模块
13 o 1.12. copy 模块
14 o 1.13. sys 模块
15 o 1.14. atexit 模块
16 o 1.15. time 模块
17 o 1.16. types 模块
18 o 1.17. gc 模块
19
20
21
22
23
24 1. 核心模块
25 "Since the functions in the C runtime library are not part of the Win32
26 API, we believe the number of applications that will be affected by this
27 bug to be very limited."
28 - Microsoft, January 1999
29 1.1. 介绍
30 Python 的标准库包括了很多的模块, 从 Python 语言自身特定的类型和声明,
31 到一些只用于少数程序的不著名的模块.
32 本章描述了一些基本的标准库模块. 任何大型 Python 程序都有可能直接或间
33 接地使用到这类模块的大部分.
34 1.1.1. 内建函数和异常
35 下面的这两个模块比其他模块加在一起还要重要: 定义内建函数(例如 len,
36 int, range ...)的 _ _builtin_ _ 模块, 以及定义所有内建异常的 exceptions
37 模块.
38 Python 在启动时导入这两个模块, 使任何程序都能够使用它们.
39 1.1.2. 操作系统接口模块
40 Python 有许多使用了 POSIX 标准 API 和标准 C 语言库的模块. 它们为底层
41 操作系统提供了平*立的接口.
42 这类的模块包括: 提供文件和进程处理功能的 os 模块; 提供平*立的文件
43 名处理 (分拆目录名, 文件名, 后缀等)的 os.path 模块; 以及时间日期处理
44 相关的 time/datetime 模块.
45 [!Feather 注: datetime 为 Py2.3 新增模块, 提供增强的时间处理方法 ]
46 延伸一点说, 网络和线程模块同样也可以归为这一个类型. 不过 Python 并没
47 有在所有的平台/版本实现这些.
48 1.1.3. 类型支持模块
49 标准库里有许多用于支持内建类型操作的库. string 模块实现了常用的字符串
50 处理. math 模块提供了数学计算操作和常量(pi, e 都属于这类常量), cmath 模
51 块为复数提供了和 math 一样的功能.
52 1.1.4. 正则表达式
53 re 模块为 Python 提供了正则表达式支持. 正则表达式是用于匹配字符串或特
54 定子字符串的有特定语法的字符串模式.
55 1.1.5. 语言支持模块
56 sys 模块可以让你访问解释器相关参数,比如模块搜索路径,解释器版本号等.
57 operator 模块提供了和内建操作符作用相同的函数. copy 模块允许你复制对
58 象, Python 2.0 新加入的 gc 模块提供了对垃圾收集的相关控制功能.
59 1.2. _ _builtin_ _ 模块
60 这个模块包含 Python 中使用的内建函数. 一般不用手动导入这个模块;
61 Python 会帮你做好一切.
62 1.2.1. 使用元组或字典中的参数调用函数
63 Python 允许你实时地创建函数参数列表. 只要把所有的参数放入一个元组中,
64 然后通过内建的 apply 函数调用函数. 如 Example 1-1 .
65 1.2.1.1. Example 1-1. 使用 apply 函数
66 File: builtin-apply-example-1.py
67 def function(a, b):
68 print a, b
69 apply(function, ("whither", "canada?"))
70 apply(function, (1, 2 + 3))
71 whither canada?
72 1 5
73 要想把关键字参数传递给一个函数, 你可以将一个字典作为 apply 函数的第 3
74 个参数, 参考 Example 1-2 .
75 1.2.1.2. Example 1-2. 使用 apply 函数传递关键字参数
76 File: builtin-apply-example-2.py
77 def function(a, b):
78 print a, b
79 apply(function, ("crunchy", "frog"))
80 apply(function, ("crunchy",), {"b": "frog"})
81 apply(function, (), {"a": "crunchy", "b": "frog"})
82 crunchy frog
83 crunchy frog
84 crunchy frog
85 apply 函数的一个常见用法是把构造函数参数从子类传递到基类, 尤其是构造
86 函数需要接受很多参数的时候. 如 Example 1-3 所示.
87 1.2.1.3. Example 1-3. 使用 apply 函数调用基类的构造函数
88 File: builtin-apply-example-3.py
89 class Rectangle:
90 def _ _init_ _(self, color="white", width=10, height=10):
91 print "create a", color, self, "sized", width, "x", height
92 class RoundedRectangle(Rectangle):
93 def _ _init_ _(self, **kw):
94 apply(Rectangle._ _init_ _, (self,), kw)
95 rect = Rectangle(color="green", height=
96 100, width=100) rect= RoundedRectangle(color=
97 "blue",
98 height = 20)< /FONT> <
99 FONT face= 宋体>
100 create a green <Rectangle instance at 8c8260> sized 100 x 100
101 create a blue <RoundedRectangle instance at 8c84c0> sized 10 x 20
102 Python 2.0 提供了另个方法来做相同的事. 你只需要使用一个传统的函数调
103 用 , 使用 * 来标记元组, ** 来标记字典.
104 下面两个语句是等价的:
105 result = function(*args, **kwargs)
106 result =
107 apply(function, args, kwargs) < /FONT
108 >
109 1.2.2. 加载和重载模块
110 如果你写过较庞大的 Python 程序, 那么你就应该知道 import 语句是用来导
111 入外部模块的 (当然也可以使用 from-import 版本). 不过你可能不知道
112 import 其实是靠调用内建函数 _ _import_ _ 来工作的.
113 通过这个戏法你可以动态地调用函数. 当你只知道模块名称(字符串)的时候,
114 这将很方便. Example 1-4 展示了这种用法, 动态地导入所有以 "-plugin " 结
115 尾的模块.
116 1.2.2.1. Example 1-4. 使用 _ _import_ _ 函数加载模块
117 File: builtin-import-example-1.py
118 import glob, os
119 modules = []
120 for module_file in glob.glob("*-plugin.py"):
121 try:
122 module_name, ext =
123 os.path.splitext(os.path.basename(module_file))
124 module = _ _import_ _(module_name)
125 modules.append(module)
126 except ImportError:
127 pass # ignore broken modules
128 # say hello to all modules
129 for module in modules:
130 module.hello()
131 example-plugin says hello
132 注意这个 plug-in 模块文件名中有个 "-" (hyphens). 这意味着你不能使用普
133 通的 import 命令, 因为 Python 的辨识符不允许有 "-" .
134 Example 1-5 展示了 Example 1-4 中使用的 plug-in .
135 1.2.2.2. Example 1-5. Plug-in 例子
136 File: example-plugin.py
137 def hello():
138 print "example-plugin says hello"
139 Example 1-6 展示了如何根据给定模块名和函数名获得想要的函数对象.
140 1.2.2.3. Example 1-6. 使用 _ _import_ _ 函数获得特定函数
141 File: builtin-import-example-2.py
142 def getfunctionbyname(module_name, function_name):
143 module = _ _import_ _(module_name)
144 return getattr(module, function_name)
145 print repr(getfunctionbyname("dumbdbm", "open"))
146 <function open at 794fa0>
147 你也可以使用这个函数实现延迟化的模块导入 (lazy module loading). 例如在
148 Example 1-7 中的 string 模块只在第一次使用的时候导入.
149 1.2.2.4. Example 1-7. 使用 _ _import_ _ 函数实现 延迟导入
150 File: builtin-import-example-3.py
151 class LazyImport:
152 def _ _init_ _(self, module_name):
153 self.module_name = module_name
154 self.module = None
155 def _ _getattr_ _(self, name):
156 if self.module is None:
157 self.module = _ _import_ _(self.module_name)
158 return getattr(self.module, name)
159 string = LazyImport("string")
160 print string.lowercase
161 abcdefghijklmnopqrstuvwxyz
162 Python 也提供了重新加载已加载模块的基本支持. [Example 1-8 #eg-1-8 会加
163 载 3 次 hello.py 文件.
164 1.2.2.5. Example 1-8. 使用 reload 函数
165 File: builtin-reload-example-1.py
166 import hello
167 reload(hello)
168 reload(hello)
169 hello again, and welcome to the show
170 hello again, and welcome to the show
171 hello again, and welcome to the show
172 reload 直接接受模块作为参数.
173 [!Feather 注: ^ 原句无法理解, 稍后讨论.]
174 注意,当你重加载模块时, 它会被重新编译, 新的模块会代替模块字典里的老模
175 块. 但是, 已经用原模块里的类建立的实例仍然使用的是老模块(不会被更新).
176 同样地, 使用 from-import 直接创建的到模块内容的引用也是不会被更新的.
177 1.2.3. 关于名称空间
178 dir 返回由给定模块, 类, 实例, 或其他类型的所有成员组成的列表. 这可能
179 在交互式 Python 解释器下很有用, 也可以用在其他地方. Example 1-9 展示了
180 dir 函数的用法.
181 1.2.3.1. Example 1-9. 使用 dir 函数
182 File: builtin-dir-example-1.py
183 def dump(value):
184 print value, "=>", dir(value)
185 import sys
186 dump(0)
187 dump(1.0)
188 dump(0.0j) # complex number
189 dump([]) # list
190 dump({}) # dictionary
191 dump("string")
192 dump(len) # function
193 dump(sys) # module
194 0 => []
195 1.0 => []
196 0j => ['conjugate', 'imag', 'real']
197 [] => ['append', 'count', 'extend', 'index', 'insert',
198 'pop', 'remove', 'reverse', 'sort']
199 {} => ['clear', 'copy',
200 'get', 'has_key',
201 'items', 'keys', 'update', 'values']
202 string =
203 > [] <built-in function
204 len> = > ['_ _doc_ _', '_
205 _name_ _', '_
206 _self_ _']
207 <module 'sys' (built-in)> =
208 > ['_ _doc_ _', '_ _name_ _',
209 '_ _stderr_ _', '_ _stdin_ _', '_ _stdout_ _', 'argv',
210 'builtin_module_names', 'copyright', 'dllhandle',
211 'exc_info', 'exc_type', 'exec_prefix', 'executable',
212 ...
213 在例子 Example 1-10 中定义的 getmember 函数返回给定类定义的所有类级别
214 的属性和方法.
215 1.2.3.2. Example 1-10. 使用 dir 函数查找类的所有成员
216 File: builtin-dir-example-2.py
217 class A:
218 def a(self):
219 pass
220 def b(self):
221 pass
222 class B(A):
223 def c(self):
224 pass
225 def d(self):
226 pass
227 def getmembers(klass, members=None):
228 # get a list of all class members, ordered by class
229 if members is None:
230 members = []
231 for k in klass._ _bases_ _:
232 getmembers(k, members)
233 for m in dir(klass):
234 if m not in members:
235 members.append(m)
236 return members
237 print getmembers(A)
238 print getmembers(B)
239 print getmembers(IOError)
240 <
241 FONT face=
242 宋体
243 >
244 ['_ _doc_ _', '_ _module_ _', 'a', 'b']
245 ['_ _doc_ _', '_ _module_ _', 'a', 'b', 'c', 'd']
246 ['_ _doc_ _', '_ _getitem_ _', '_ _init_ _', '_ _module_ _', '_ _str_
247 _']
248 getmembers 函数返回了一个有序列表. 成员在列表中名称出现的越早, 它所处
249 的类层次就越高. 如果无所谓顺序的话, 你可以使用字典代替列表.
250 [!Feather 注: 字典是无序的, 而列表和元组是有序的, 网上有关于有序字典
251 的讨论]
252 vars 函数与此相似, 它返回的是包含每个成员当前值的字典. 如果你使用不带
253 参数的 vars , 它将返回当前局部名称空间的可见元素(同 locals() 函数 ).
254 如 Example 1-11 所表示.
255 1.2.3.3. Example 1-11. 使用 vars 函数
256 File: builtin-vars-example-1.py
257 book = "library2"
258 pages = 250
259 scripts = 350
260 print "the %(book)s book contains more than %(scripts)s scripts" % vars()
261 the library book contains more than 350 scripts
262 1.2.4. 检查对象类型
263 Python 是一种动态类型语言, 这意味着给一个定变量名可以在不同的场合绑定
264 到不同的类型上. 在接下面例子中, 同样的函数分别被整数, 浮点数, 以及一
265 个字符串调用:
266 def function(value):
267 print value
268 function(1)
269 function(1.0)
270 function("one")
271 type 函数 (如 Example 1-12 所示) 允许你检查一个变量的类型. 这个函数会
272 返回一个 type descriptor (类型描述符) , 它对于 Python 解释器提供的每个
273 类型都是不同的.
274 1.2.4.1. Example 1-12. 使用 type 函数
275 File: builtin-type-example-1.py
276 def dump(value):
277 print type(value), value
278 dump(1)
279 dump(1.0)
280 dump("one")
281 <type 'int'> 1
282 <type 'float'> 1.0
283 <type 'string'> one
284 每个类型都有一个对应的类型对象, 所以你可以使用 is 操作符 (对象身份?)
285 来检查类型. (如 Example 1-13 所示).
286 1.2.4.2. Example 1-13. 对文件名和文件对象使用 type 函数
287 File: builtin-type-example-2.py
288 def load(file):
289 if isinstance(file, type("")):
290 file = open(file, "rb")
291 return file.read()
292 print len(load("samples/sample.jpg")), "bytes"
293 print len(load(open("samples/sample.jpg", "rb"))), "bytes"
294 4672 bytes
295 4672 bytes
296 callable 函数, 如 Example 1-14 所示, 可以检查一个对象是否是可调用的
297 (无论是直接调用或是通过 apply ). 对于函数, 方法, lambda 函式, 类, 以及
298 实现了 _ _call_ _ 方法的类实例, 它都返回 True.
299 1.2.4.3. Example 1-14. 使用 callable 函数
300 File: builtin-callable-example-1.py
301 def dump(function):
302 if callable(function):
303 print function, "is callable"
304 else:
305 print function, "is *not* callable"
306 class A:
307 def method(self, value):
308 return value
309 class B(A):
310 def _ _call_ _(self, value):
311 return value
312 a = A()
313 b = B()
314 dump(0) # simple objects
315 dump("string")
316 dump(callable)
317 dump(dump) # function
318 dump(A) # classes
319 dump(B)
320 dump(B.method)
321 dump(a) # instances
322 dump(b)
323 dump(b.method)
324 <
325 FONT
326 face =
327 宋体
328 >
329 0 is *not* callable
330 string is *not* callable
331 <built-in function callable> is callable
332 <function dump at 8ca320> is callable
333 A is callable
334 B is callable
335 <unbound method A.method> is callable
336 <A instance at 8caa10> is *not* callable
337 <B instance at 8cab00> is callable
338 <method A.method of B instance at 8cab00> is callable
339 注意类对象 (A 和 B) 都是可调用的; 如果调用它们, 就产生新的对象(类实
340 例). 但是 A 类的实例不可调用, 因为它的类没有实现 _ _call_ _ 方法.
341 你可以在 operator 模块中找到检查对象是否为某一内建类型(数字, 序列, 或
342 者字典等) 的函数. 但是, 因为创建一个类很简单(比如实现基本序列方法的
343 类), 所以对这些类型使用显式的类型判断并不是好主意.
344 在处理类和实例的时候会复杂些. Python 不会把类作为本质上的类型对待; 相
345 反地, 所有的类都属于一个特殊的类类型(special class type), 所有的类实例
346 属于一个特殊的实例类型(special instance type).
347 这意味着你不能使用 type 函数来测试一个实例是否属于一个给定的类; 所有
348 的实例都是同样的类型! 为了解决这个问题, 你可以使用 isinstance 函数,它
349 会检查一个对象是不是给定类(或其子类)的实例. Example 1-15 展示了
350 isinstance 函数的使用.
351 1.2.4.4. Example 1-15. 使用 isinstance 函数
352 File: builtin-isinstance-example-1.py
353 class A:
354 pass
355 class B:
356 pass
357 class C(A):
358 pass
359 class D(A, B):
360 pass
361 def dump(object):
362 print object, "=>",
363 if isinstance(object, A):
364 print "A",
365 if isinstance(object, B):
366 print "B",
367 if isinstance(object, C):
368 print "C",
369 if isinstance(object, D):
370 print "D",
371 print
372 a = A()
373 b =
374 B() c=
375 C()
376 d =
377 D()
378 dump(a) dump(b)
379 dump(c)
380 dump(d)
381 dump(0)
382 dump("string")< /FONT
383 > < FONT
384 face =
385 宋体
386 >
387 <A instance at 8ca6d0> => A
388 <B instance at 8ca750> => B
389 <C instance at 8ca780> =
390 > A C
391 <D instance at 8ca7b0> = >
392 A B D 0 = >
393 string =
394 >
395 issubclass 函数与此相似, 它用于检查一个类对象是否与给定类相同, 或者是
396 给定类的子类. 如 Example 1-16 所示.
397 注意, isinstance 可以接受任何对象作为参数, 而 issubclass 函数在接受非
398 类对象参数时会引发 TypeError 异常.
399 1.2.4.5. Example 1-16. 使用 issubclass 函数
400 File: builtin-issubclass-example-1.py
401 class A:
402 pass
403 class B:
404 pass
405 class C(A):
406 pass
407 class D(A, B):
408 pass
409 def dump(object):
410 print object, "=>",
411 if issubclass(object, A):
412 print "A",
413 if issubclass(object, B):
414 print "B",
415 if issubclass(object, C):
416 print "C",
417 if issubclass(object, D):
418 print "D",
419 print
420 dump(A)
421 dump(B)
422 dump(C)
423 dump(D)
424 dump(0)
425 dump("string")
426 A => A
427 B => B
428 C => A C
429 D = >
430 A B D
431 0 =
432 >
433 Traceback (innermost last):
434 File "builtin-issubclass-example-1.py", line 29, in ?
435 File "builtin-issubclass-example-1.py", line 15, in dump
436 TypeError: arguments must be classes
437 1.2.5. 计算 Python 表达式
438 Python 提供了在程序中与解释器交互的多种方法. 例如 eval 函数将一个字符
439 串作为 Python 表达式求值. 你可以传递一串文本, 简单的表达式, 或者使用
440 内建 Python 函数. 如 Example 1-17 所示.
441 1.2.5.1. Example 1-17. 使用 eval 函数
442 File: builtin-eval-example-1.py
443 def dump(expression):
444 result = eval(expression)
445 print expression, "=>", result, type(result)
446 dump("1")
447 dump("1.0")
448 dump("'string'")
449 dump("1.0 + 2.0")
450 dump("'*' * 10")
451 dump("len('world')")
452 <
453 FONT
454 face =
455 宋体>
456 1 => 1 <type 'int'>
457 1.0 => 1.0 <type 'float'>
458 'string' = > string
459 <type 'string'> 1.0 +
460 2.0 = >
461 3.0 <type 'float'> '*' * 10=
462 > ********** <type 'string'> len('world')=
463 > 5 <type 'int'>
464 如果你不确定字符串来源的安全性, 那么你在使用 eval 的时候会遇到些麻烦.
465 例如, 某个用户可能会使用 _ _import_ _ 函数加载 os 模块, 然后从硬盘删除
466 文件 (如 Example 1-18 所示).
467 1.2.5.2. Example 1-18. 使用 eval 函数执行任意命令
468 File: builtin-eval-example-2.py
469 print eval("_ _import_ _('os').getcwd()")
470 print eval("_ _import_ _('os').remove('file')")
471 /home/fredrik/librarybook Traceback (innermost
472 last): File "builtin-eval-example-2", line 2, in
473 ? File"<string>", line 0, in ?
474 os.error: (2, 'No such file or directory')
475 这里我们得到了一个 os.error 异常, 这说明 Python 事实上在尝试删除文件!
476 幸运地是, 这个问题很容易解决. 你可以给 eval 函数传递第 2 个参数, 一个
477 定义了该表达式求值时名称空间的字典. 我们测试下, 给函数传递个空字典:
478 >>> print eval("_ _import_
479 _('os').remove('file')", {}) Traceback
480 (innermost last):File "<stdin>", line 1, in
481 ? File"<string>", line 0, in ?
482 os.error: (2, 'No such file or directory')
483 呃.... 我们还是得到了个 os.error 异常.
484 这是因为 Python 在求值前会检查这个字典, 如果没有发现名称为 _
485 _builtins_ _ 的变量(复数形式), 它就会添加一个:
486 >>> namespace = {} >>>
487 print eval("_ _import_ _('os').remove('file')", namespace)
488 Traceback (innermost last):
489 File "<stdin>",line 1, in ? File
490 "<string>", line0, in ? os.error: (2,
491 'No such file or directory') >>> namespace.keys()
492 ['_
493 _builtins_ _'] <
494 /FONT >
495 如果你打印这个 namespace 的内容, 你会发现里边有所有的内建函数.
496 [!Feather 注: 如果我RP 不错的话, 添加的这个_ _builtins_ _就是当前的_
497 _builtins_ _]
498 我们注意到了如果这个变量存在, Python 就不会去添加默认的, 那么我们的解
499 决方法也来了, 为传递的字典参数加入一个 _ _builtins_ _ 项即可. 如
500 Example 1-19 所示.
501 1.2.5.3. Example 1-19. 安全地使用 eval 函数求值
502 File: builtin-eval-example-3.py
503 print eval("_ _import_ _('os').getcwd()", {})
504 print eval("_ _import_ _('os').remove('file')", {"_ _builtins_ _": {}})
505 /home/fredrik/librarybook Traceback (innermost
506 last): File "builtin-eval-example-3.py", line 2, in
507 ? File"<string>", line 0, in ?
508 NameError: _ _import_ _
509 即使这样, 你仍然无法避免针对 CPU 和内存资源的攻击. (比如, 形如
510 eval("'*'*1000000*2*2*2*2*2*2*2*2*2") 的语句在执行后会使你的程序耗尽
511 系统资源).
512 1.2.6. 编译和执行代码
513 eval 函数只针对简单的表达式. 如果要处理大块的代码, 你应该使用 compile
514 和 exec 函数 (如 Example 1-20 所示).
515 1.2.6.1. Example 1-20. 使用 compile 函数检查语法
516 File: builtin-compile-example-1.py
517 NAME = "script.py"
518 BODY =
519 """ prnt
520 'owl-stretching time' """
521 try:
522 compile(BODY,
523 NAME, "exec") except
524 SyntaxError, v: print
525 "syntax error:", v, "in", NAME #
526 syntax error: invalid syntax in script.py
527 < /FONT
528 >
529 成功执行后, compile 函数会返回一个代码对象, 你可以使用 exec 语句执行
530 它, 参见 Example 1-21 .
531 1.2.6.2. Example 1-21. 执行已编译的代码
532 File: builtin-compile-example-2.py
533 BODY = """
534 print 'the ant, an introduction'
535 """
536 code = compile(BODY,"<script>", "exec")
537 print code
538 exec code
539 < FONT
540 face =
541 宋体
542 >
543 <code object ? at 8c6be0, file"<script>", line 0>
544 the ant, an introduction
545 使用 Example 1-22 中的类可以在程序执行时实时地生成代码. write 方法用于
546 添加代码, indent 和 dedent 方法用于控制缩进结构. 其他部分交给类来处
547 理.
548 1.2.6.3. Example 1-22. 简单的代码生成工具
549 File: builtin-compile-example-3.py
550 import sys, string
551 class CodeGeneratorBackend:
552 "Simple code generator for Python"
553 def begin(self, tab="\t"):
554 self.code = []
555 self.tab = tab
556 self.level = 0
557 def end(self):
558 self.code.append("") # make sure there's a newline at the end
559 return compile(string.join(self.code, "\n"), "<code>", "exec")
560 def write(self, string):
561 self.code.append(self.tab * self.level + string)
562 def indent(self):
563 self.level = self.level +
564 1 # in
565 2.0 and
566 later, this can be written
567 as: self.level +=
568 1 def
569 dedent(self): if
570 self.level =
571 =
572 0:
573 raise SyntaxError, "internal error in
574 code generator"
575 self.level =
576 self.level- 1
577 # or:
578 self.level - =
579 1
580 #
581 # try
582 it out!
583 c =
584 CodeGeneratorBackend()
585 c.begin() c.write("for
586 i in range(5):") c.indent()
587 c.write("print 'code generation made easy!'") c.dedent() exec
588 c.end()< /FONT > < FONT
589 face =
590 宋体
591 >
592 code generation made easy!
593 code generation made easy!
594 code generation made easy!
595 code generation made easy!
596 code generation made easy!
597 Python 还提供了 execfile 函数, 一个从文件加载代码, 编译代码, 执行代码
598 的快捷方式. Example 1-23 简单地展示了如何使用这个函数.
599 1.2.6.4. Example 1-23. 使用 execfile 函数
600 File: builtin-execfile-example-1.py
601 execfile("hello.py")
602 def EXECFILE(filename, locals=None, globals=None):
603 exec compile(open(filename).read(), filename, "exec") in locals,
604 globals
605 EXECFILE("hello.py")
606 <
607 FONT face= 宋体>
608 hello again, and welcome to the show
609 hello again, and welcome to the show
610 Example 1-24 中的代码是 Example 1-23 中使用的 hello.py 文件.
611 1.2.6.5. Example 1-24. hello.py 脚本
612 File: hello.py
613 print "hello again, and welcome to the show"
614 1.2.7. 从 _ _builtin_ _ 模块重载函数
615 因为 Python 在检查局部名称空间和模块名称空间前不会检查内建函数, 所以
616 有时候你可能要显式地引用 _ _builtin_ _ 模块. 例如 Example 1-25 重载了
617 内建的 open 函数. 这时候要想使用原来的 open 函数, 就需要脚本显式地指
618 明模块名称.
619 1.2.7.1. Example 1-25. 显式地访问 _ _builtin_ _ 模块中的函数
620 File: builtin-open-example-1.py
621 def open(filename, mode="rb"):
622 import _ _builtin_ _
623 file = _ _builtin_ _.open(filename, mode)
624 if file.read(5) not in("GIF87", "GIF89"): raise
625 IOError, "not aGIF
626 file" file.seek(0) return file
627 fp =
628 open("samples/sample.gif")
629 print
630 len(fp.read()), "bytes"
631 fp =
632 open("samples/sample.jpg") print
633 len(fp.read()), "bytes"
634 < /FONT> <
635 FONT
636 face=
637 宋体
638 >
639 3565 bytes
640 Traceback (innermost last):
641 File "builtin-open-example-1.py", line 12, in ?
642 File "builtin-open-example-1.py", line 5, in open
643 IOError: not a GIF file
644 [!Feather 注: 明白这个open()函数是干什么的么? 检查一个文件是否是 GIF
645 文件,
646 一般如这类的图片格式都在文件开头有默认的格式.
647 另外打开文件推荐使用file()而不是open() , 虽然暂时没有区别]
648 1.3. exceptions 模块
649 exceptions 模块提供了标准异常的层次结构. Python 启动的时候会自动导入
650 这个模块, 并且将它加入到 _ _builtin_ _ 模块中. 也就是说, 一般不需要手
651 动导入这个模块.
652 在 1.5.2 版本时它是一个普通模块, 2.0 以及以后版本成为内建模块.
653 该模块定义了以下标准异常:
654 • Exception 是所有异常的基类. 强烈建议(但不是必须)自定义的异常异
655 常也继承这个类.
656 • SystemExit(Exception) 由 sys.exit 函数引发. 如果它在最顶层没有
657 被 try-except 语句捕获, 那么解释器将直接关闭而不会显示任何跟踪
658 返回信息.
659 • StandardError(Exception) 是所有内建异常的基类(除 SystemExit
660 外).
661 • KeyboardInterrupt(StandardError) 在用户按下 Control-C(或其他打
662 断按键)后 被引发. 如果它可能会在你使用 "捕获所有" 的 try-except
663 语句时导致奇怪的问题.
664 • ImportError(StandardError) 在 Python 导入模块失败时被引发.
665 • EnvironmentError 作为所有解释器环境引发异常的基类. (也就是说,
666 这些异常一般不是由于程序 bug 引起).
667 • IOError(EnvironmentError) 用于标记 I/O 相关错误.
668 • OSError(EnvironmentError) 用于标记 os 模块引起的错误.
669 • WindowsError(OSError) 用于标记 os 模块中 Windows 相关错误.
670 • NameError(StandardError) 在 Python 查找全局或局部名称失败时被引
671 发.
672 • UnboundLocalError(NameError) , 当一个局部变量还没有赋值就被使用
673 时, 会引发这个异常. 这个异常只有在2.0 及之后的版本有; 早期版本
674 只会引发一个普通的 NameError .
675 • AttributeError(StandardError) , 当 Python 寻找(或赋值)给一个实
676 例属性, 方法, 模块功能或其它有效的命名失败时, 会引发这个异常.
677 • SyntaxError(StandardError) , 当解释器在编译时遇到语法错误, 这个
678 异常就被引发.
679 • (2.0 及以后版本) IndentationError(SyntaxError) 在遇到非法的缩进
680 时被引发. 该异常只用于 2.0 及以后版本, 之前版本会引发一个
681 SyntaxError 异常.
682 • (2.0 及以后版本) TabError(IndentationError) , 当使用 -tt 选项检
683 查不一致缩进时有可能被引发. 该异常只用于 2.0 及以后版本, 之前版
684 本会引发一个 SyntaxError 异常.
685 • TypeError(StandardError) , 当给定类型的对象不支持一个操作时被引
686 发.
687 • AssertionError(StandardError) 在 assert 语句失败时被引发(即表达
688 式为 false 时).
689 • LookupError(StandardError) 作为序列或字典没有包含给定索引或键时
690 所引发异常的基类.
691 • IndexError(LookupError) , 当序列对象使用给定索引数索引失败时(不
692 存在索引对应对象)引发该异常.
693 • KeyError(LookupError) 当字典对象使用给定索引索引失败时(不存在索
694 引对应对象)引发该异常.
695 • ArithmeticError(StandardError) 作为数学计算相关异常的基类.
696 • OverflowError(ArithmeticError) 在操作溢出时被引发(例如当一个整
697 数太大, 导致不能符合给定类型).
698 • ZeroDivisionError(ArithmeticError) , 当你尝试用 0 除某个数时被
699 引发.
700 • FloatingPointError(ArithmeticError) , 当浮点数操作失败时被引发.
701 • ValueError(StandardError) , 当一个参数类型正确但值不合法时被引
702 发.
703 • (2.0 及以后版本) UnicodeError(ValueError) , Unicode 字符串类型相
704 关异常. 只使用在 2.0 及以后版本.
705 • RuntimeError(StandardError) , 当出现运行时问题时引发, 包括在限
706 制模式下尝试访问外部内容, 未知的硬件问题等等.
707 • NotImplementedError(RuntimeError) , 用于标记未实现的函数, 或无
708 效的方法.
709 • SystemError(StandardError) , 解释器内部错误. 该异常值会包含更多
710 的细节 (经常会是一些深层次的东西, 比如 "eval_code2: NULL
711 globals" ) . 这本书的作者编了 5 年程序都没见过这个错误. (想必是
712 没有用 raise SystemError ).
713 • MemoryError(StandardError) , 当解释器耗尽内存时会引发该异常. 注
714 意只有在底层内存分配抱怨时这个异常才会发生; 如果是在你的旧机器
715 上, 这个异常发生之前系统会陷入混乱的内存交换中.
716 你可以创建自己的异常类. 只需要继承内建的 Exception 类(或者它的任意一
717 个合适的子类)即可, 有需要时可以再重载它的 _ _str_ _ 方法. Example 1-26
718 展示了如何使用 exceptions 模块.
719 1.3.0.1. Example 1-26. 使用 exceptions 模块
720 File: exceptions-example-1.py
721 # python imports this module by itself, so the following
722 # line isn't really needed
723 # python 会自动导入该模块, 所以以下这行是不必要的
724 # import exceptions
725 class HTTPError(Exception):
726 # indicates an HTTP protocol error
727 def _ _init_ _(self, url, errcode, errmsg):
728 self.url = url
729 self.errcode = errcode
730 self.errmsg =
731 errmsg def _ _str_ _(self):
732 return ( "<HTTPError for %s: %s %s>"
733 % (self.url,
734 self.errcode, self.errmsg)
735 ) try:
736 raise HTTPError("http://www.python.org/foo", 200, "Not
737 Found") except
738 HTTPError, error: print "url", "=
739 >", error.url
740 print "errcode", "=>", error.errcode
741 print "errmsg", "=
742 >",
743 error.errmsg raise #
744 reraise exception
745 < /FONT
746 >
747 <
748 FONT face=
749 宋体>
750 url => http://www.python.org/foo
751 errcode => 200
752 errmsg =
753 > Not Found
754 Traceback (innermost last):
755 File "exceptions-example-1", line 16, in ?
756 HTTPError: <HTTPError for http://www.python.org/foo: 200 Not Found>
757 1.4. os 模块
758 这个模块中的大部分函数通过对应平台相关模块实现, 比如 posix 和 nt. os
759 模块会在第一次导入的时候自动加载合适的执行模块.
760 1.4.1. 处理文件
761 内建的 open / file 函数用于创建, 打开和编辑文件, 如 Example 1-27 所示.
762 而 os 模块提供了重命名和删除文件所需的函数.
763 1.4.1.1. Example 1-27. 使用 os 模块重命名和删除文件
764 File: os-example-3.py
765 import os
766 import string
767 def replace(file, search_for, replace_with):
768 # replace strings in a text file
769 back = os.path.splitext(file)[0] + ".bak"
770 temp = os.path.splitext(file)[0] + ".tmp"
771 try:
772 # remove old temp file, if any
773 os.remove(temp)
774 except os.error:
775 pass
776 fi = open(file)
777 fo = open(temp, "w")
778 for s in
779 fi.readlines(): fo.write(string.replace(s,
780 search_for, replace_with))
781 fi.close() fo.close() try: #
782 remove old backup file, if any os.remove(back)
783 except os.error: pass #
784 rename original to backup...
785 os.rename(file,
786 back) # ...and temporary to original os.rename(temp,
787 file)
788 # #
789 try
790 it out!
791 file =
792 "samples/sample.txt"
793 replace(file,
794 "hello", "tjena")
795 replace(file,
796 "tjena", "hello")
797 < /FONT
798 >
799 1.4.2. 处理目录
800 os 模块也包含了一些用于目录处理的函数.
801 listdir 函数返回给定目录中所有文件名(包括目录名)组成的列表, 如
802 Example 1-28 所示. 而 Unix 和 Windows 中使用的当前目录和父目录标记(.
803 和 .. )不包含在此列表中.
804 1.4.2.1. Example 1-28. 使用 os 列出目录下的文件
805 File: os-example-5.py
806 import os
807 for file in os.listdir("samples"):
808 print file
809 sample.au
810 sample.jpg
811 sample.wav
812 ...
813 getcwd 和 chdir 函数分别用于获得和改变当前工作目录. 如 Example 1-29
814 所示.
815 1.4.2.2. Example 1-29. 使用 os 模块改变当前工作目录
816 File: os-example-4.py
817 import os
818 # where are we?
819 cwd = os.getcwd()
820 print "1", cwd
821 # go down
822 os.chdir("samples")
823 print "2", os.getcwd()
824 # go back up
825 os.chdir(os.pardir)
826 print "3", os.getcwd()
827 1 /ematter/librarybook
828 2 /ematter/librarybook/samples
829 3 /ematter/librarybook
830 makedirs 和 removedirs 函数用于创建或删除目录层,如 Example 1-30 所示.
831 1.4.2.3. Example 1-30. 使用 os 模块创建/删除多个目录级
832 File: os-example-6.py
833 import os
834 os.makedirs("test/multiple/levels")
835 fp =
836 open("test/multiple/levels/file", "w") fp.write("inspector
837 praline") fp.close()
838 #
839 remove the file os.remove("test/multiple/levels/file")
840 #
841 and all empty directories above it os.removedirs("test/multiple/levels")
842 <
843 /FONT
844 >
845 removedirs 函数会删除所给路径中最后一个目录下所有的空目录. 而 mkdir
846 和 rmdir 函数只能处理单个目录级. 如 Example 1-31 所示.
847 1.4.2.4. Example 1-31. 使用 os 模块创建/删除目录
848 File: os-example-7.py
849 import os
850 os.mkdir("test")
851 os.rmdir("test")
852 os.rmdir("samples") # this will fail
853 Traceback (innermost last):
854 File "os-example-7", line 6, in ?
855 OSError: [Errno 41] Directory not empty: 'samples'
856 如果需要删除非空目录, 你可以使用 shutil 模块中的 rmtree 函数.
857 1.4.3. 处理文件属性
858 stat 函数可以用来获取一个存在文件的信息, 如 Example 1-32 所示. 它返回
859 一个类元组对象(stat_result 对象, 包含 10 个元素), 依次是st_mode (权限
860 模式), st_ino (inode number), st_dev (device), st_nlink (number of hard
861 links), st_uid (所有者用户 ID), st_gid (所有者所在组 ID ), st_size (文
862 件大小, 字节), st_atime (最近一次访问时间), st_mtime (最近修改时间),
863 st_ctime (平台相关; Unix 下的最近一次元数据/metadata 修改时间, 或者
864 Windows 下的创建时间) - 以上项目也可作为属性访问.
865 [!Feather 注: 原文为 9 元元组. 另,返回对象并非元组类型,为 struct.]
866 1.4.3.1. Example 1-32. 使用 os 模块获取文件属性
867 File: os-example-1.py
868 import os
869 import time
870 file = "samples/sample.jpg"
871 def dump(st):
872 mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime = st
873 print "- size:", size, "bytes"
874 print "- owner:", uid, gid
875 print "- created:", time.ctime(ctime)
876 print "- last accessed:", time.ctime(atime)
877 print "- last modified:", time.ctime(mtime)
878 print "- mode:", oct(mode)
879 print "- inode/dev:", ino, dev
880 #
881 # get stats for a filename
882 st =
883 os.stat(file)
884 print "stat",
885 file dump(st)
886 print # # get stats for an open file fp =
887 open(file)
888 st =
889 os.fstat(fp.fileno())
890 print "fstat",
891 file
892 dump(st) <
893 /FONT >
894 < FON
895 T
896 face =
897 宋体
898 >
899 stat samples/sample.jpg
900 - size: 4762 bytes
901 - owner: 0 0
902 - created: Tue Sep 07 22:45:58 1999
903 - last accessed: Sun Sep 19 00:00:00 1999
904 - last modified: Sun May 19 01:42:16 1996
905 - mode: 0100666
906 - inode/dev: 0 2
907 fstat samples/sample.jpg
908 - size: 4762 bytes
909 - owner: 0 0
910 - created: Tue Sep 07 22:45:58 1999
911 - last accessed: Sun Sep 19 00:00:00 1999
912 - last modified: Sun May 19 01:42:16 1996
913 - mode: 0100666
914 - inode/dev: 0 0
915 返回对象中有些属性在非 Unix 平台下是无意义的, 比如 (st_inode , st_dev )
916 为 Unix 下的为每个文件提供了唯一标识, 但在其他平台可能为任意无意义数
917 据 .
918 stat 模块包含了很多可以处理该返回对象的常量及函数. 下面的代码展示了其
919 中的一些.
920 可以使用 chmod 和 utime 函数修改文件的权限模式和时间属性,如 Example
921 1-33 所示.
922 1.4.3.2. Example 1-33. 使用 os 模块修改文件的权限和时间戳
923 File: os-example-2.py
924 import os
925 import stat, time
926 infile = "samples/sample.jpg"
927 outfile = "out.jpg"
928 # copy contents
929 fi = open(infile, "rb")
930 fo = open(outfile, "wb")
931 while 1:
932 s = fi.read(10000)
933 if not s:
934 break fo.write(s)
935 fi.close() fo.close()
936 # copy mode
937 and timestamp
938 st =
939 os.stat(infile) os.chmod(outfile, stat.S_IMODE(st[stat.ST_MODE]))
940 os.utime(outfile, (st[stat.ST_ATIME], st[stat.ST_MTIME]))
941 print "original",
942 " =
943 >" print "mode",
944 oct(stat.S_IMODE(st[stat.ST_MODE]))
945 print
946 "atime",
947 time.ctime(st[stat.ST_ATIME])
948 print "mtime", time.ctime(st[stat.ST_MTIME]) print "copy",
949 " =
950 >" st=
951 os.stat(outfile)
952 print "mode",
953 oct(stat.S_IMODE(st[stat.ST_MODE]))
954 print
955 "atime", time.ctime(st[stat.ST_ATIME]) print
956 "mtime", time.ctime(st[stat.ST_MTIME]) <
957 /FONT >
958 < FONT
959 face =
960 宋体
961 >
962 original =>
963 mode 0666
964 atime Thu Oct 14 15:15:50 1999
965 mtime Mon Nov 13 15:42:36 1995
966 copy =
967 >
968 mode 0666
969 atime Thu Oct 14 15:15:50 1999
970 mtime Mon Nov 13 15:42:36 1995
971 1.4.4. 处理进程
972 system 函数在当前进程下执行一个新命令, 并等待它完成, 如 Example 1-34
973 所示.
974 1.4.4.1. Example 1-34. 使用 os 执行操作系统命令
975 File: os-example-8.py
976 import os
977 if os.name == "nt":
978 command =
979 "dir" else:
980 command = "ls
981 -l"
982 os.system(command) < /FONT
983 ><
984 FONT
985 face =
986 宋体
987 >
988 -rwxrw-r-- 1 effbot effbot 76 Oct 9 14:17 README
989 -rwxrw-r-- 1 effbot effbot 1727 Oct 7 19:00
990 SimpleAsyncHTTP.py
991 -rwxrw-r-- 1 effbot effbot 314 Oct 7 20:29 aifc-example-1.py
992 -rwxrw-r-- 1 effbot effbot 259 Oct 7 20:38
993 anydbm-example-1.py
994 ...
995 命令通过操作系统的标准 shell 执行, 并返回 shell 的退出状态. 需要注意
996 的是在 Windows 95/98 下, shell 通常是 command.com , 它的推出状态总是
997 0.
998 由于 11os.system11 直接将命令传递给 shell , 所以如果你不检查传入参数
999 的时候会很危险 (比如命令 os.system("viewer %s" % file) , 将 file 变量
1000 设置为 "sample.jpg; rm -rf $HOME" .... ). 如果不确定参数的安全性, 那么
1001 最好使用 exec 或 spawn 代替(稍后介绍).
1002 exec 函数会使用新进程替换当前进程(或者说是"转到进程"). 在 Example
1003 1-35 中, 字符串 "goodbye" 永远不会被打印.
1004 1.4.4.2. Example 1-35. 使用 os 模块启动新进程
1005 File: os-exec-example-1.py
1006 import os
1007 import sys
1008 program = "python"
1009 arguments = ["hello.py"]
1010 print os.execvp(program, (program,) + tuple(arguments))
1011 print "goodbye"
1012 hello again, and welcome to the show
1013 Python 提供了很多表现不同的 exec 函数. Example 1-35 使用的是 execvp 函
1014 数, 它会从标准路径搜索执行程序, 把第二个参数(元组)作为单独的参数传递
1015 给程序, 并使用当前的环境变量来运行程序. 其他七个同类型函数请参阅
1016 Python Library Reference .
1017 在 Unix 环境下, 你可以通过组合使用 exec , fork 以及 wait 函数来从当前
1018 程序调用另一个程序, 如 Example 1-36 所示. fork 函数复制当前进程, wait
1019 函数会等待一个子进程执行结束.
1020 1.4.4.3. Example 1-36. 使用 os 模块调用其他程序 (Unix)
1021 File: os-exec-example-2.py
1022 import os
1023 import sys
1024 def run(program, *args):
1025 pid = os.fork()
1026 if not pid:
1027 os.execvp(program, (program,) + args)
1028 return os.wait()[0]
1029 run("python", "hello.py")
1030 print "goodbye"
1031 hello again, and welcome to the show
1032 goodbye
1033 fork 函数在子进程返回中返回 0 (这个进程首先从 fork 返回值), 在父进程
1034 中返回一个非 0 的进程标识符(子进程的 PID ). 也就是说, 只有当我们处于
1035 子进程的时候 "not pid " 才为真.
1036 fork 和 wait 函数在 Windows 上是不可用的, 但是你可以使用 spawn 函数,
1037 如 Example 1-37 所示. 不过, spawn 不会沿着路径搜索可执行文件, 你必须自
1038 己处理好这些.
1039 1.4.4.4. Example 1-37. 使用 os 模块调用其他程序 (Windows)
1040 File: os-spawn-example-1.py
1041 import os
1042 import string
1043 def run(program, *args):
1044 # find executable
1045 for path in string.split(os.environ["PATH"], os.pathsep):
1046 file = os.path.join(path, program) + ".exe"
1047 try:
1048 return os.spawnv(os.P_WAIT, file, (file,) + args)
1049 except os.error:
1050 pass
1051 raise os.error, "cannot find executable"
1052 run("python", "hello.py")
1053 print "goodbye"
1054 hello again, and welcome to the show
1055 goodbye
1056 spawn 函数还可用于在后台运行一个程序. Example 1-38 给 run 函数添加了一
1057 个可选的 mode 参数; 当设置为 os.P_NOWAIT 时, 这个脚本不会等待子程序结
1058 束, 默认值 os.P_WAIT 时 spawn 会等待子进程结束.
1059 其它的标志常量还有 os.P_OVERLAY ,它使得 spawn 的行为和 exec 类似, 以
1060 及 os.P_DETACH , 它在后台运行子进程, 与当前控制台和键盘焦点隔离.
1061 1.4.4.5. Example 1-38. 使用 os 模块在后台执行程序 (Windows)
1062 File: os-spawn-example-2.py
1063 import os
1064 import string
1065 def run(program, *args, **kw):
1066 # find executable
1067 mode = kw.get("mode", os.P_WAIT)
1068 for path in string.split(os.environ["PATH"], os.pathsep):
1069 file = os.path.join(path, program) + ".exe"
1070 try:
1071 return os.spawnv(mode, file, (file,) + args)
1072 except os.error:
1073 pass
1074 raise os.error, "cannot find executable"
1075 run("python", "hello.py", mode=os.P_NOWAIT)
1076 print "goodbye"
1077 <
1078 FONT
1079 face =
1080 宋体>
1081 goodbye
1082 hello again, and welcome to the show
1083 Example 1-39 提供了一个在 Unix 和 Windows 平台上通用的 spawn 方法.
1084 1.4.4.6. Example 1-39. 使用 spawn 或 fork/exec 调用其他程序
1085 File: os-spawn-example-3.py
1086 import os
1087 import string
1088 if os.name in ("nt", "dos"):
1089 exefile = ".exe"
1090 else:
1091 exefile = ""
1092 def spawn(program, *args):
1093 try:
1094 # possible 2.0 shortcut!
1095 return os.spawnvp(program, (program,) + args)
1096 except AttributeError:
1097 pass
1098 try:
1099 spawnv =
1100 os.spawnv except
1101 AttributeError: # assume it's unix
1102 pid =
1103 os.fork() if
1104 not pid: os.execvp(program,
1105 (program,)
1106 + args) return os.wait()[0]
1107 else: # got spawnv but
1108 no spawnp:
1109 go
1110 look
1111 for an
1112 executable for
1113 path in string.split(os.environ["PATH"], os.pathsep):
1114 file =
1115 os.path.join(path, program) +
1116 exefile try: return spawnv(os.P_WAIT, file,
1117 (file,)
1118 + args) except os.error: pass raise
1119 IOError, "cannot
1120 find
1121 executable" # # try
1122 it out!
1123 spawn("python", "hello.py")
1124 print "goodbye" < /FONT >
1125 < FONT
1126 face =
1127 宋体
1128 >
1129 hello again, and welcome to the show
1130 goodbye
1131 Example 1-39 首先尝试调用 spawnvp 函数. 如果该函数不存在 (一些版本/平
1132 台没有这个函数), 它将继续查找一个名为 spawnv 的函数并且开始查找程序路
1133 径. 作为最后的选择, 它会调用 exec 和 fork 函数完成工作.
1134 1.4.5. 处理守护进程(Daemon Processes)
1135 Unix 系统中, 你可以使用 fork 函数把当前进程转入后台(一个"守护者
1136 /daemon"). 一般来说, 你需要派生(fork off)一个当前进程的副本, 然后终止
1137 原进程, 如 Example 1-40 所示.
1138 1.4.5.1. Example 1-40. 使用 os 模块使脚本作为守护执行 (Unix)
1139 File: os-example-14.py
1140 import os
1141 import time
1142 pid =
1143 os.fork() if
1144 pid: os._exit(0)
1145 # kill original print
1146 "daemon started" time.sleep(10)
1147 print
1148 "daemon terminated" <
1149 /FONT
1150 >
1151 需要创建一个真正的后台程序稍微有点复杂, 首先调用 setpgrp 函数创建一个
1152 "进程组首领/process group leader". 否则, 向无关进程组发送的信号(同时)
1153 会引起守护进程的问题:
1154 os.setpgrp()
1155 为了确保守护进程创建的文件能够获得程序指定的 mode flags(权限模式标
1156 记?), 最好删除 user mode mask:
1157 os.umask(0)
1158 然后, 你应该重定向 stdout/stderr 文件, 而不能只是简单地关闭它们(如果
1159 你的程序需要 stdout 或 stderr 写入内容的时候, 可能会出现意想不到的问
1160 题).
1161 class NullDevice:
1162 def write(self, s):
1163 pass
1164 sys.stdin.close()
1165 sys.stdout =
1166 NullDevice()
1167 sys.stderr =
1168 NullDevice()
1169 < /FONT
1170 >
1171 换言之, 由于 Python 的 print 和 C 中的 printf/fprintf 在设备(device)
1172 没有连接后不会关闭你的程序, 此时守护进程中的 sys.stdout.write() 会抛
1173 出一个 IOError 异常, 而你的程序依然在后台运行的很好....
1174 另外, 先前例子中的 _exit 函数会终止当前进程. 而 sys.exit 不同, 如果调
1175 用者(caller) 捕获了 SystemExit 异常, 程序仍然会继续执行. 如 Example
1176 1-41 所示.
1177 1.4.5.2. Example 1-41. 使用 os 模块终止当前进程
1178 File: os-example-9.py
1179 import os
1180 import sys
1181 try:
1182 sys.exit(1)
1183 except SystemExit, value:
1184 print "caught exit(%s)" % value
1185 try:
1186 os._exit(2)
1187 except SystemExit, value:
1188 print "caught exit(%s)" % value
1189 print "bye!"
1190 caught exit(1)
1191 1.5. os.path 模块
1192 os.path 模块包含了各种处理长文件名(路径名)的函数. 先导入 (import) os
1193 模块, 然后就可以以 os.path 访问该模块.
1194 1.5.1. 处理文件名
1195 os.path 模块包含了许多与平台无关的处理长文件名的函数. 也就是说, 你不
1196 需要处理前后斜杠, 冒号等. 我们可以看看 Example 1-42 中的样例代码.
1197 1.5.1.1. Example 1-42. 使用 os.path 模块处理文件名
1198 File: os-path-example-1.py
1199 import os
1200 filename = "my/little/pony"
1201 print "using", os.name, "..."
1202 print "split", "=>", os.path.split(filename)
1203 print "splitext", "=>", os.path.splitext(filename)
1204 print "dirname", "=>", os.path.dirname(filename)
1205 print "basename", "=>", os.path.basename(filename)
1206 print "join",
1207 " =
1208 >", os.path.join(os.path.dirname(filename),
1209 os.path.basename(filename))<
1210 /FONT>
1211 <
1212 FONT face=
1213 宋体>
1214 using nt ...
1215 split => ('my/little', 'pony')
1216 splitext => ('my/little/pony', '')
1217 dirname = > my/little
1218 basename =
1219 > pony
1220 join =
1221 > my/little\pony
1222 注意这里的 split 只分割出最后一项(不带斜杠).
1223 os.path 模块中还有许多函数允许你简单快速地获知文件名的一些特征,如
1224 Example 1-43 所示。
1225 1.5.1.2. Example 1-43. 使用 os.path 模块检查文件名的特征
1226 File: os-path-example-2.py
1227 import os
1228 FILES = (
1229 os.curdir,
1230 "/",
1231 "file",
1232 "/file",
1233 "samples",
1234 "samples/sample.jpg",
1235 "directory/file",
1236 "../directory/file",
1237 "/directory/file"
1238 )
1239 for file in FILES:
1240 print file, "=>",
1241 if os.path.exists(file):
1242 print "EXISTS",
1243 if os.path.isabs(file):
1244 print "ISABS",
1245 if os.path.isdir(file):
1246 print "ISDIR",
1247 if os.path.isfile(file):
1248 print "ISFILE",
1249 if os.path.islink(file):
1250 print "ISLINK",
1251 if os.path.ismount(file):
1252 print "ISMOUNT",
1253 print
1254 <
1255 FONT
1256 face =
1257 宋体>
1258 . => EXISTS ISDIR
1259 / => EXISTS ISABS ISDIR ISMOUNT
1260 file =>
1261 /file => ISABS
1262 samples => EXISTS ISDIR
1263 samples/sample.jpg => EXISTS ISFILE
1264 directory/file =>
1265 ../directory/file =>
1266 /directory/file => ISABS
1267 expanduser 函数以与大部分Unix shell 相同的方式处理用户名快捷符号(~, 不
1268 过在 Windows 下工作不正常), 如 Example 1-44 所示.
1269 1.5.1.3. Example 1-44. 使用 os.path 模块将用户名插入到文件名
1270 File: os-path-expanduser-example-1.py
1271 import os
1272 print os.path.expanduser("~/.pythonrc")
1273 # /home/effbot/.pythonrc
1274 expandvars 函数将文件名中的环境变量替换为对应值, 如 Example 1-45 所
1275 示.
1276 1.5.1.4. Example 1-45. 使用 os.path 替换文件名中的环境变量
1277 File: os-path-expandvars-example-1.py
1278 import os
1279 os.environ["USER"] = "user"
1280 print os.path.expandvars("/home/$USER/config")
1281 print os.path.expandvars("$USER/folders")
1282 /home/user/config
1283 user/folders
1284 1.5.2. 搜索文件系统
1285 walk 函数会帮你找出一个目录树下的所有文件 (如 Example 1-46 所示). 它
1286 的参数依次是目录名, 回调函数, 以及传递给回调函数的数据对象.
1287 1.5.2.1. Example 1-46. 使用 os.path 搜索文件系统
1288 File: os-path-walk-example-1.py
1289 import os
1290 def callback(arg, directory, files):
1291 for file in files:
1292 print os.path.join(directory, file), repr(arg)
1293 os.path.walk(".", callback, "secret message")
1294 ./aifc-example-1.py 'secret message'
1295 ./anydbm-example-1.py 'secret message'
1296 ./array-example-1.py 'secret message'
1297 ...
1298 ./samples 'secret message'
1299 ./samples/sample.jpg 'secret message'
1300 ./samples/sample.txt 'secret message'
1301 ./samples/sample.zip 'secret message'
1302 ./samples/articles 'secret message'
1303 ./samples/articles/article-1.txt 'secret message'
1304 ./samples/articles/article-2.txt 'secret message'
1305 ...
1306 walk 函数的接口多少有点晦涩 (也许只是对我个人而言, 我总是记不住参数的
1307 顺序). Example 1-47 中展示的 index 函数会返回一个文件名列表, 你可以直
1308 接使用 for-in 循环处理文件.
1309 1.5.2.2. Example 1-47. 使用 os.listdir 搜索文件系统
1310 File: os-path-walk-example-2.py
1311 import os
1312 def index(directory):
1313 # like os.listdir, but traverses directory trees
1314 stack = [directory]
1315 files = []
1316 while stack:
1317 directory = stack.pop()
1318 for file in os.listdir(directory):
1319 fullname = os.path.join(directory, file)
1320 files.append(fullname)
1321 if os.path.isdir(fullname) and not
1322 os.path.islink(fullname):
1323 stack.append(fullname)
1324 return files
1325 for file in index("."):
1326 print file
1327 .\aifc-example-1.py
1328 .\anydbm-example-1.py
1329 .\array-example-1.py
1330 ...
1331 如果你不想列出所有的文件 (基于性能或者是内存的考虑) , Example 1-48 展
1332 示了另一种方法. 这里 DirectoryWalker 类的行为与序列对象相似, 一次返回
1333 一个文件. (generator?)
1334 1.5.2.3. Example 1-48. 使用 DirectoryWalker 搜索文件系统
1335 File: os-path-walk-example-3.py
1336 import os
1337 class DirectoryWalker:
1338 # a forward iterator that traverses a directory tree
1339 def _ _init_ _(self, directory):
1340 self.stack = [directory]
1341 self.files = []
1342 self.index = 0
1343 def _ _getitem_ _(self, index):
1344 while 1:
1345 try:
1346 file = self.files[self.index]
1347 self.index = self.index + 1
1348 except IndexError:
1349 # pop next directory from stack
1350 self.directory = self.stack.pop()
1351 self.files = os.listdir(self.directory)
1352 self.index = 0
1353 else:
1354 # got a filename
1355 fullname = os.path.join(self.directory, file)
1356 if os.path.isdir(fullname) and not
1357 os.path.islink(fullname):
1358 self.stack.append(fullname)
1359 return fullname
1360 for file in DirectoryWalker("."):
1361 print file
1362 .\aifc-example-1.py
1363 .\anydbm-example-1.py
1364 .\array-example-1.py
1365 ...
1366 注意 DirectoryWalker 类并不检查传递给 _ _getitem_ _ 方法的索引值. 这意
1367 味着如果你越界访问序列成员(索引数字过大)的话, 这个类将不能正常工作.
1368 最后, 如果你需要处理文件大小和时间戳, Example 1-49 给出了一个类, 它返
1369 回文件名和它的 os.stat 属性(一个元组). 这个版本在每个文件上都能节省一
1370 次或两次 stat 调用( os.path.isdir 和 os.path.islink 内部都使用了
1371 stat ), 并且在一些平台上运行很快.
1372 1.5.2.4. Example 1-49. 使用 DirectoryStatWalker 搜索文件系统
1373 File: os-path-walk-example-4.py
1374 import os, stat
1375 class DirectoryStatWalker:
1376 # a forward iterator that traverses a directory tree, and
1377 # returns the filename and additional file information
1378 def _ _init_ _(self, directory):
1379 self.stack = [directory]
1380 self.files = []
1381 self.index = 0
1382 def _ _getitem_ _(self, index):
1383 while 1:
1384 try:
1385 file = self.files[self.index]
1386 self.index = self.index + 1
1387 except IndexError:
1388 # pop next directory from stack
1389 self.directory = self.stack.pop()
1390 self.files = os.listdir(self.directory)
1391 self.index = 0
1392 else:
1393 # got a filename
1394 fullname = os.path.join(self.directory, file)
1395 st = os.stat(fullname)
1396 mode = st[stat.ST_MODE]
1397 if stat.S_ISDIR(mode) and not stat.S_ISLNK(mode):
1398 self.stack.append(fullname)
1399 return fullname, st
1400 for file, st in DirectoryStatWalker("."):
1401 print file, st[stat.ST_SIZE]
1402 .\aifc-example-1.py 336
1403 .\anydbm-example-1.py 244
1404 .\array-example-1.py 526
1405 1.6. stat 模块
1406 Example 1-50 展示了 stat 模块的基本用法, 这个模块包含了一些 os.stat
1407 函数中可用的常量和测试函数.
1408 1.6.0.1. Example 1-50. Using the stat Module
1409 File: stat-example-1.py
1410 import stat
1411 import os, time
1412 st = os.stat("samples/sample.txt")
1413 print "mode", "=>", oct(stat.S_IMODE(st[stat.ST_MODE]))
1414 print "type", "=>",
1415 if stat.S_ISDIR(st[stat.ST_MODE]):
1416 print "DIRECTORY",
1417 if stat.S_ISREG(st[stat.ST_MODE]):
1418 print "REGULAR",
1419 if stat.S_ISLNK(st[stat.ST_MODE]):
1420 print "LINK",
1421 print
1422 print "size", "=>", st[stat.ST_SIZE]
1423 print "last accessed", "=>", time.ctime(st[stat.ST_ATIME])
1424 print "last modified", "=>", time.ctime(st[stat.ST_MTIME])
1425 print "inode changed", "=>", time.ctime(st[stat.ST_CTIME])
1426 mode => 0664
1427 type => REGULAR
1428 size => 305
1429 last accessed => Sun Oct 10 22:12:30 1999
1430 last modified => Sun Oct 10 18:39:37 1999
1431 inode changed => Sun Oct 10 15:26:38 1999
1432 1.7. string 模块
1433 string 模块提供了一些用于处理字符串类型的函数, 如 Example 1-51 所示.
1434 1.7.0.1. Example 1-51. 使用 string 模块
1435 File: string-example-1.py
1436 import string
1437 text = "Monty Python's Flying Circus"
1438 print "upper", "=>", string.upper(text)
1439 print "lower", "=>", string.lower(text)
1440 print "split", "=>", string.split(text)
1441 print "join", "=>", string.join(string.split(text), "+")
1442 print "replace", "=>", string.replace(text, "Python", "Java")
1443 print "find", "=>", string.find(text, "Python"), string.find(text,
1444 "Java")
1445 print "count", "=>", string.count(text, "n")
1446 upper => MONTY PYTHON'S FLYING CIRCUS
1447 lower => monty python's flying circus
1448 split => ['Monty', "Python's", 'Flying', 'Circus']
1449 join => Monty+Python's+Flying+Circus
1450 replace => Monty Java's Flying Circus
1451 find => 6 -1
1452 count => 3
1453 在 Python 1.5.2 以及更早版本中, string 使用 strop 中的函数来实现模块功
1454 能.
1455 在 Python1.6 和后继版本,更多的字符串操作都可以作为字符串方法来访问,
1456 如 Example 1-52 所示, string 模块中的许多函数只是对相对应字符串方法的
1457 封装.
1458 1.7.0.2. Example 1-52. 使用字符串方法替代 string 模块函数
1459 File: string-example-2.py
1460 text = "Monty Python's Flying Circus"
1461 print "upper", "=>", text.upper()
1462 print "lower", "=>", text.lower()
1463 print "split", "=>", text.split()
1464 print "join", "=>", "+".join(text.split())
1465 print "replace", "=>", text.replace("Python", "Perl")
1466 print "find", "=>", text.find("Python"), text.find("Perl")
1467 print "count", "=>", text.count("n")
1468 upper => MONTY PYTHON'S FLYING CIRCUS
1469 lower => monty python's flying circus
1470 split => ['Monty', "Python's", 'Flying', 'Circus']
1471 join => Monty+Python's+Flying+Circus
1472 replace => Monty Perl's Flying Circus
1473 find => 6 -1
1474 count => 3
1475 为了增强模块对字符的处理能力, 除了字符串方法, string 模块还包含了类型
1476 转换函数用于把字符串转换为其他类型, (如 Example 1-53 所示).
1477 1.7.0.3. Example 1-53. 使用 string 模块将字符串转为数字
1478 File: string-example-3.py
1479 import string
1480 print int("4711"),
1481 print string.atoi("4711"),
1482 print string.atoi("11147", 8), # octal 八进制
1483 print string.atoi("1267", 16), # hexadecimal 十六进制
1484 print string.atoi("3mv", 36) # whatever...
1485 print string.atoi("4711", 0),
1486 print string.atoi("04711", 0),
1487 print string.atoi("0x4711", 0)
1488 print float("4711"),
1489 print string.atof("1"),
1490 print string.atof("1.23e5")
1491 4711 4711 4711 4711 4711
1492 4711 2505 18193
1493 4711.0 1.0 123000.0
1494 大多数情况下 (特别是当你使用的是1.6 及更高版本时) ,你可以使用 int 和
1495 float 函数代替 string 模块中对应的函数。
1496 atoi 函数可以接受可选的第二个参数, 指定数基(number base). 如果数基为
1497 0, 那么函数将检查字符串的前几个字符来决定使用的数基: 如果为 "0x," 数
1498 基将为 16 (十六进制), 如果为 "0," 则数基为 8 (八进制). 默认数基值为 10
1499 (十进制), 当你未传递参数时就使用这个值.
1500 在 1.6 及以后版本中, int 函数和 atoi 一样可以接受第二个参数. 与字符串
1501 版本函数不一样的是 , int 和 float 可以接受 Unicode 字符串对象.
1502 1.8. re 模块
1503 "Some people, when confronted with a problem, think 'I know, I'll use
1504 regular expressions.' Now they have two problems."
1505 - Jamie Zawinski, on comp.lang.emacs
1506 re 模块提供了一系列功能强大的正则表达式 (regular expression) 工具, 它
1507 们允许你快速检查给定字符串是否与给定的模式匹配 (使用 match 函数), 或
1508 者包含这个模式 (使用 search 函数). 正则表达式是以紧凑(也很神秘)的语法
1509 写出的字符串模式.
1510 match 尝试从字符串的起始匹配一个模式, 如 Example 1-54 所示. 如果模式
1511 匹配了某些内容 (包括空字符串, 如果模式允许的话) , 它将返回一个匹配对
1512 象. 使用它的 group 方法可以找出匹配的内容.
1513 1.8.0.1. Example 1-54. 使用 re 模块来匹配字符串
1514 File: re-example-1.py
1515 import re
1516 text = "The Attila the Hun Show"
1517 # a single character 单个字符
1518 m = re.match(".", text)
1519 if m: print repr("."), "=>", repr(m.group(0))
1520 # any string of characters 任何字符串
1521 m = re.match(".*", text)
1522 if m: print repr(".*"), "=>", repr(m.group(0))
1523 # a string of letters (at least one) 只包含字母的字符串(至少一个)
1524 m = re.match("\w+", text)
1525 if m: print repr("\w+"), "=>", repr(m.group(0))
1526 # a string of digits 只包含数字的字符串
1527 m = re.match("\d+", text)
1528 if m: print repr("\d+"), "=>", repr(m.group(0))
1529 '.' => 'T'
1530 '.*' => 'The Attila the Hun Show'
1531 '\\w+' => 'The'
1532 可以使用圆括号在模式中标记区域. 找到匹配后, group 方法可以抽取这些区
1533 域的内容,如 Example 1-55 所示. group(1) 会返回第一组的内容, group(2)
1534 返回第二组的内容, 这样... 如果你传递多个组数给 group 函数, 它会返回一
1535 个元组.
1536 1.8.0.2. Example 1-55. 使用 re 模块抽出匹配的子字符串
1537 File: re-example-2.py
1538 import re
1539 text ="10/15/99"
1540 m = re.match("(\d{2})/(\d{2})/(\d{2,4})", text)
1541 if m:
1542 print m.group(1, 2, 3)
1543 ('10', '15', '99')
1544 search 函数会在字符串内查找模式匹配, 如 Example 1-56 所示. 它在所有可
1545 能的字符位置尝试匹配模式, 从最左边开始, 一旦找到匹配就返回一个匹配对
1546 象. 如果没有找到相应的匹配, 就返回 None .
1547 1.8.0.3. Example 1-56. 使用 re 模块搜索子字符串
1548 File: re-example-3.py
1549 import re
1550 text = "Example 3: There is 1 date 10/25/95 in here!"
1551 m = re.search("(\d{1,2})/(\d{1,2})/(\d{2,4})", text)
1552 print m.group(1), m.group(2), m.group(3)
1553 month, day, year = m.group(1, 2, 3)
1554 print month, day, year
1555 date = m.group(0)
1556 print date
1557 10 25 95
1558 10 25 95
1559 10/25/95
1560 Example 1-57 中展示了 sub 函数, 它可以使用另个字符串替代匹配模式.
1561 1.8.0.4. Example 1-57. 使用 re 模块替换子字符串
1562 File: re-example-4.py
1563 import re
1564 text = "you're no fun anymore..."
1565 # literal replace (string.replace is faster)
1566 # 文字替换 (string.replace 速度更快)
1567 print re.sub("fun", "entertaining", text)
1568 # collapse all non-letter sequences to a single dash
1569 # 将所有非字母序列转换为一个"-"(dansh,破折号)
1570 print re.sub("[^\w]+", "-", text)
1571 # convert all words to beeps
1572 # 将所有单词替换为 BEEP
1573 print re.sub("\S+", "-BEEP-", text)
1574 you're no entertaining anymore...
1575 you-re-no-fun-anymore-
1576 -BEEP- -BEEP- -BEEP- -BEEP-
1577 你也可以通过回调 (callback) 函数使用 sub 来替换指定模式. Example 1-58
1578 展示了如何预编译模式.
1579 1.8.0.5. Example 1-58. 使用 re 模块替换字符串(通过回调函数)
1580 File: re-example-5.py
1581 import re
1582 import string
1583 text = "a line of text\\012another line of text\\012etc..."
1584 def octal(match):
1585 # replace octal code with corresponding ASCII character
1586 # 使用对应 ASCII 字符替换八进制代码
1587 return chr(string.atoi(match.group(1), 8))
1588 octal_pattern = re.compile(r"\\(\d\d\d)")
1589 print text
1590 print octal_pattern.sub(octal, text)
1591 a line of text\012another line of text\012etc...
1592 a line of text
1593 another line of text
1594 etc...
1595 如果你不编译, re 模块会为你缓存一个编译后版本, 所有的小脚本中, 通常不
1596 需要编译正则表达式. Python1.5.2 中, 缓存中可以容纳 20 个匹配模式, 而
1597 在 2.0 中, 缓存则可以容纳 100 个匹配模式.
1598 最后, Example 1-59 用一个模式列表匹配一个字符串. 这些模式将会组合为一
1599 个模式, 并预编译以节省时间.
1600 1.8.0.6. Example 1-59. 使用 re 模块匹配多个模式中的一个
1601 File: re-example-6.py
1602 import re, string
1603 def combined_pattern(patterns):
1604 p = re.compile(
1605 string.join(map(lambda x: "("+x+")", patterns), "|")
1606 )
1607 def fixup(v, m=p.match, r=range(0,len(patterns))):
1608 try:
1609 regs = m(v).regs
1610 except AttributeError:
1611 return None # no match, so m.regs will fail
1612 else:
1613 for i in r:
1614 if regs[i+1] != (-1, -1):
1615 return i
1616 return fixup
1617 #
1618 # try it out!
1619 patterns = [
1620 r"\d+",
1621 r"abc\d{2,4}",
1622 r"p\w+"
1623 ]
1624 p = combined_pattern(patterns)
1625 print p("129391")
1626 print p("abc800")
1627 print p("abc1600")
1628 print p("python")
1629 print p("perl")
1630 print p("tcl")
1631 0
1632 1
1633 1
1634 2
1635 2
1636 None
1637 1.9. math 模块
1638 math 模块实现了许多对浮点数的数学运算函数. 这些函数一般是对平台 C 库
1639 中同名函数的简单封装, 所以一般情况下, 不同平台下计算的结果可能稍微地
1640 有所不同, 有时候甚至有很大出入. Example 1-60 展示了如何使用 math 模块.
1641 1.9.0.1. Example 1-60. 使用 math 模块
1642 File: math-example-1.py
1643 import math
1644 print "e", "=>", math.e
1645 print "pi", "=>", math.pi
1646 print "hypot", "=>", math.hypot(3.0, 4.0)
1647 # and many others...
1648 e => 2.71828182846
1649 pi => 3.14159265359
1650 hypot => 5.0
1651 完整函数列表请参阅 Python Library Reference .
1652 1.10. cmath 模块
1653 Example 1-61 所展示的 cmath 模块包含了一些用于复数运算的函数.
1654 1.10.0.1. Example 1-61. 使用 cmath 模块
1655 File: cmath-example-1.py
1656 import cmath
1657 print "pi", "=>", cmath.pi
1658 print "sqrt(-1)", "=>", cmath.sqrt(-1)
1659 pi => 3.14159265359
1660 sqrt(-1) => 1j
1661 完整函数列表请参阅 Python Library Reference .
1662 1.11. operator 模块
1663 operator 模块为 Python 提供了一个 "功能性" 的标准操作符接口. 当使用
1664 map 以及 filter 一类的函数的时候, operator 模块中的函数可以替换一些
1665 lambda 函式. 而且这些函数在一些喜欢写晦涩代码的程序员中很流行.
1666 Example 1-62 展示了 operator 模块的一般用法.
1667 1.11.0.1. Example 1-62. 使用 operator 模块
1668 File: operator-example-1.py
1669 import operator
1670 sequence = 1, 2, 4
1671 print "add", "=>", reduce(operator.add, sequence)
1672 print "sub", "=>", reduce(operator.sub, sequence)
1673 print "mul", "=>", reduce(operator.mul, sequence)
1674 print "concat", "=>", operator.concat("spam", "egg")
1675 print "repeat", "=>", operator.repeat("spam", 5)
1676 print "getitem", "=>", operator.getitem(sequence, 2)
1677 print "indexOf", "=>", operator.indexOf(sequence, 2)
1678 print "sequenceIncludes", "=>", operator.sequenceIncludes(sequence, 3)
1679 add => 7
1680 sub => -5
1681 mul => 8
1682 concat => spamegg
1683 repeat => spamspamspamspamspam
1684 getitem => 4
1685 indexOf => 1
1686 sequenceIncludes => 0
1687 Example 1-63 展示了一些可以用于检查对象类型的 operator 函数.
1688 1.11.0.2. Example 1-63. 使用 operator 模块检查类型
1689 File: operator-example-2.py
1690 import operator
1691 import UserList
1692 def dump(data):
1693 print type(data), "=>",
1694 if operator.isCallable(data):
1695 print "CALLABLE",
1696 if operator.isMappingType(data):
1697 print "MAPPING",
1698 if operator.isNumberType(data):
1699 print "NUMBER",
1700 if operator.isSequenceType(data):
1701 print "SEQUENCE",
1702 print
1703 dump(0)
1704 dump("string")
1705 dump("string"[0])
1706 dump([1, 2, 3])
1707 dump((1, 2, 3))
1708 dump({"a": 1})
1709 dump(len) # function 函数
1710 dump(UserList) # module 模块
1711 dump(UserList.UserList) # class 类
1712 dump(UserList.UserList()) # instance 实例
1713 <type 'int'> => NUMBER
1714 <type 'string'> => SEQUENCE
1715 <type 'string'> => SEQUENCE
1716 <type 'list'> => SEQUENCE
1717 <type 'tuple'> => SEQUENCE
1718 <type 'dictionary'> => MAPPING
1719 <type 'builtin_function_or_method'> => CALLABLE
1720 <type 'module'> =>
1721 <type 'class'> => CALLABLE
1722 <type 'instance'> => MAPPING NUMBER SEQUENCE
1723 这里需要注意 operator 模块使用非常规的方法处理对象实例. 所以使用
1724 isNumberType , isMappingType , 以及 isSequenceType 函数的时候要小心,
1725 这很容易降低代码的扩展性.
1726 同样需要注意的是一个字符串序列成员 (单个字符) 也是序列. 所以当在递归
1727 函数使用 isSequenceType 来截断对象树的时候, 别把普通字符串作为参数(或
1728 者是任何包含字符串的序列对象).
1729 1.12. copy 模块
1730 copy 模块包含两个函数, 用来拷贝对象, 如 Example 1-64 所示.
1731 copy(object) => object 创建给定对象的 "浅/浅层(shallow)" 拷贝(copy).
1732 这里 "浅/浅层(shallow)" 的意思是复制对象本身, 但当对象是一个容器
1733 (container) 时, 它的成员仍然指向原来的成员对象.
1734 1.12.0.1. Example 1-64. 使用 copy 模块复制对象
1735 File: copy-example-1.py
1736 import copy
1737 a = [[1],[2],[3]]
1738 b = copy.copy(a)
1739 print "before", "=>"
1740 print a
1741 print b
1742 # modify original
1743 a[0][0] = 0
1744 a[1] = None
1745 print "after", "=>"
1746 print a
1747 print b
1748 before =>
1749 [[1], [2], [3]]
1750 [[1], [2], [3]]
1751 after =>
1752 [[0], None, [3]]
1753 [[0], [2], [3]]
1754 你也可以使用[:]语句 (完整切片) 来对列表进行浅层复制, 也可以使用 copy
1755 方法复制字典.
1756 相反地, deepcopy(object) => object 创建一个对象的深层拷贝(deepcopy),
1757 如 Example 1-65 所示, 当对象为一个容器时, 所有的成员都被递归地复制了。
1758 1.12.0.2. Example 1-65. 使用 copy 模块复制集合(Collections)
1759 File: copy-example-2.py
1760 import copy
1761 a = [[1],[2],[3]]
1762 b = copy.deepcopy(a)
1763 print "before", "=>"
1764 print a
1765 print b
1766 # modify original
1767 a[0][0] = 0
1768 a[1] = None
1769 print "after", "=>"
1770 print a
1771 print b
1772 before =>
1773 [[1], [2], [3]]
1774 [[1], [2], [3]]
1775 after =>
1776 [[0], None, [3]]
1777 [[1], [2], [3]]
1778 1.13. sys 模块
1779 sys 模块提供了许多函数和变量来处理 Python 运行时环境的不同部分.
1780 1.13.1. 处理命令行参数
1781 在解释器启动后, argv 列表包含了传递给脚本的所有参数, 如 Example 1-66
1782 所示. 列表的第一个元素为脚本自身的名称.
1783 1.13.1.1. Example 1-66. 使用sys 模块获得脚本的参数
1784 File: sys-argv-example-1.py
1785 import sys
1786 print "script name is", sys.argv[0]
1787 if len(sys.argv) > 1:
1788 print "there are", len(sys.argv)-1, "arguments:"
1789 for arg in sys.argv[1:]:
1790 print arg
1791 else:
1792 print "there are no arguments!"
1793 script name is sys-argv-example-1.py
1794 there are no arguments!
1795 如果是从标准输入读入脚本 (比如 "python < sys-argv-example-1.py "), 脚
1796 本的名称将被设置为空串. 如果把脚本作为字符串传递给python (使用 -c 选
1797 项), 脚本名会被设置为 "-c".
1798 1.13.2. 处理模块
1799 path 列表是一个由目录名构成的列表, Python 从中查找扩展模块( Python 源
1800 模块, 编译模块,或者二进制扩展). 启动 Python 时,这个列表从根据内建规则,
1801 PYTHONPATH 环境变量的内容, 以及注册表( Windows 系统)等进行初始化. 由
1802 于它只是一个普通的列表, 你可以在程序中对它进行操作, 如 Example 1-67
1803 所示.
1804 1.13.2.1. Example 1-67. 使用sys 模块操作模块搜索路径
1805 File: sys-path-example-1.py
1806 import sys
1807 print "path has", len(sys.path), "members"
1808 # add the sample directory to the path
1809 sys.path.insert(0, "samples")
1810 import sample
1811 # nuke the path
1812 sys.path = []
1813 import random # oops!
1814 path has 7 members
1815 this is the sample module!
1816 Traceback (innermost last):
1817 File "sys-path-example-1.py", line 11, in ?
1818 import random # oops!
1819 ImportError: No module named random
1820 builtin_module_names 列表包含 Python 解释器中所有内建模块的名称,
1821 Example 1-68 给出了它的样例代码.
1822 1.13.2.2. Example 1-68. 使用sys 模块查找内建模块
1823 File: sys-builtin-module-names-example-1.py
1824 import sys
1825 def dump(module):
1826 print module, "=>",
1827 if module in sys.builtin_module_names:
1828 print "<BUILTIN>"
1829 else:
1830 module = _ _import_ _(module)
1831 print module._ _file_ _
1832 dump("os")
1833 dump("sys")
1834 dump("string")
1835 dump("strop")
1836 dump("zlib")
1837 os => C:\python\lib\os.pyc
1838 sys => <BUILTIN>
1839 string => C:\python\lib\string.pyc
1840 strop => <BUILTIN>
1841 zlib => C:\python\zlib.pyd
1842 modules 字典包含所有加载的模块. import 语句在从磁盘导入内容之前会先检
1843 查这个字典.
1844 正如你在 Example 1-69 中所见到的, Python 在处理你的脚本之前就已经导入
1845 了很多模块.
1846 1.13.2.3. Example 1-69. 使用sys 模块查找已导入的模块
1847 File: sys-modules-example-1.py
1848 import sys
1849 print sys.modules.keys()
1850 ['os.path', 'os', 'exceptions', '_ _main_ _', 'ntpath', 'strop', 'nt',
1851 'sys', '_ _builtin_ _', 'site', 'signal', 'UserDict', 'string', 'stat']
1852 1.13.3. 处理引用记数
1853 getrefcount 函数 (如 Example 1-70 所示) 返回给定对象的引用记数 - 也就
1854 是这个对象使用次数. Python 会跟踪这个值, 当它减少为0 的时候, 就销毁这
1855 个对象.
1856 1.13.3.1. Example 1-70. 使用sys 模块获得引用记数
1857 File: sys-getrefcount-example-1.py
1858 import sys
1859 variable = 1234
1860 print sys.getrefcount(0)
1861 print sys.getrefcount(variable)
1862 print sys.getrefcount(None)
1863 50
1864 3
1865 192
1866 注意这个值总是比实际的数量大, 因为该函数本身在确定这个值的时候依赖这
1867 个对象.
1868 == 检查主机平台===
1869 Example 1-71 展示了 platform 变量, 它包含主机平台的名称.
1870 1.13.3.2. Example 1-71. 使用sys 模块获得当前平台
1871 File: sys-platform-example-1.py
1872 import sys
1873 #
1874 # emulate "import os.path" (sort of)...
1875 if sys.platform == "win32":
1876 import ntpath
1877 pathmodule = ntpath
1878 elif sys.platform == "mac":
1879 import macpath
1880 pathmodule = macpath
1881 else:
1882 # assume it's a posix platform
1883 import posixpath
1884 pathmodule = posixpath
1885 print pathmodule
1886 典型的平台有Windows 9X/NT(显示为 win32 ), 以及 Macintosh(显示为 mac ) .
1887 对于 Unix 系统而言, platform 通常来自 "uname -r " 命令的输出, 例如
1888 irix6 , linux2 , 或者 sunos5 (Solaris).
1889 1.13.4. 跟踪程序
1890 setprofiler 函数允许你配置一个分析函数(profiling function). 这个函数
1891 会在每次调用某个函数或方法时被调用(明确或隐含的), 或是遇到异常的时候
1892 被调用. 让我们看看 Example 1-72 的代码.
1893 1.13.4.1. Example 1-72. 使用sys 模块配置分析函数
1894 File: sys-setprofiler-example-1.py
1895 import sys
1896 def test(n):
1897 j = 0
1898 for i in range(n):
1899 j = j + i
1900 return n
1901 def profiler(frame, event, arg):
1902 print event, frame.f_code.co_name, frame.f_lineno, "->", arg
1903 # profiler is activated on the next call, return, or exception
1904 # 分析函数将在下次函数调用, 返回, 或异常时激活
1905 sys.setprofile(profiler)
1906 # profile this function call
1907 # 分析这次函数调用
1908 test(1)
1909 # disable profiler
1910 # 禁用分析函数
1911 sys.setprofile(None)
1912 # don't profile this call
1913 # 不会分析这次函数调用
1914 test(2)
1915 call test 3 -> None
1916 return test 7 -> 1
1917 基于该函数, profile 模块提供了一个完整的分析器框架.
1918 Example 1-73 中的 settrace 函数与此类似, 但是 trace 函数会在解释器每
1919 执行到新的一行时被调用.
1920 1.13.4.2. Example 1-73. 使用sys 模块配置单步跟踪函数
1921 File: sys-settrace-example-1.py
1922 import sys
1923 def test(n):
1924 j = 0
1925 for i in range(n):
1926 j = j + i
1927 return n
1928 def tracer(frame, event, arg):
1929 print event, frame.f_code.co_name, frame.f_lineno, "->", arg
1930 return tracer
1931 # tracer is activated on the next call, return, or exception
1932 # 跟踪器将在下次函数调用, 返回, 或异常时激活
1933 sys.settrace(tracer)
1934 # trace this function call
1935 # 跟踪这次函数调用
1936 test(1)
1937 # disable tracing
1938 # 禁用跟踪器
1939 sys.settrace(None)
1940 # don't trace this call
1941 # 不会跟踪这次函数调用
1942 test(2)
1943 call test 3 -> None
1944 line test 3 -> None
1945 line test 4 -> None
1946 line test 5 -> None
1947 line test 5 -> None
1948 line test 6 -> None
1949 line test 5 -> None
1950 line test 7 -> None
1951 return test 7 -> 1
1952 基于该函数提供的跟踪功能, pdb 模块提供了完整的调试( debug )框架.
1953 1.13.5. 处理标准输出/输入
1954 stdin , stdout , 以及 stderr 变量包含与标准 I/O 流对应的流对象. 如果需
1955 要更好地控制输出,而 print 不能满足你的要求, 它们就是你所需要的. 你也
1956 可以 替换 它们, 这时候你就可以重定向输出和输入到其它设备( device ), 或
1957 者以非标准的方式处理它们. 如 Example 1-74 所示.
1958 1.13.5.1. Example 1-74. 使用sys 重定向输出
1959 File: sys-stdout-example-1.py
1960 import sys
1961 import string
1962 class Redirect:
1963 def _ _init_ _(self, stdout):
1964 self.stdout = stdout
1965 def write(self, s):
1966 self.stdout.write(string.lower(s))
1967 # redirect standard output (including the print statement)
1968 # 重定向标准输出(包括print 语句)
1969 old_stdout = sys.stdout
1970 sys.stdout = Redirect(sys.stdout)
1971 print "HEJA SVERIGE",
1972 print "FRISKT HUM\303\226R"
1973 # restore standard output
1974 # 恢复标准输出
1975 sys.stdout = old_stdout
1976 print "M\303\205\303\205\303\205\303\205L!"
1977 heja sverige friskt hum\303\266r
1978 M\303\205\303\205\303\205\303\205L!
1979 要重定向输出只要创建一个对象, 并实现它的 write 方法.
1980 (除非 C 类型的实例外:Python 使用一个叫做 softspace 的整数属性来控制输
1981 出中的空白. 如果没有这个属性, Python 将把这个属性附加到这个对象上. 你
1982 不需要在使用 Python 对象时担心, 但是在重定向到一个 C 类型时, 你应该确
1983 保该类型支持 softspace 属性.)
1984 1.13.6. 退出程序
1985 执行至主程序的末尾时,解释器会自动退出. 但是如果需要中途退出程序, 你可
1986 以调用 sys.exit 函数, 它带有一个可选的整数参数返回给调用它的程序.
1987 Example 1-75 给出了范例.
1988 1.13.6.1. Example 1-75. 使用sys 模块退出程序
1989 File: sys-exit-example-1.py
1990 import sys
1991 print "hello"
1992 sys.exit(1)
1993 print "there"
1994 hello
1995 注意 sys.exit 并不是立即退出. 而是引发一个 SystemExit 异常. 这意味着
1996 你可以在主程序中捕获对 sys.exit 的调用, 如 Example 1-76 所示.
1997 1.13.6.2. Example 1-76. 捕获sys.exit 调用
1998 File: sys-exit-example-2.py
1999 import sys
2000 print "hello"
2001 try:
2002 sys.exit(1)
2003 except SystemExit:
2004 pass
2005 print "there"
2006 hello
2007 there
2008 如果准备在退出前自己清理一些东西(比如删除临时文件), 你可以配置一个 "
2009 退出处理函数"(exit handler), 它将在程序退出的时候自动被调用. 如
2010 Example 1-77 所示.
2011 1.13.6.3. Example 1-77. 另一种捕获sys.exit 调用的方法
2012 File: sys-exitfunc-example-1.py
2013 import sys
2014 def exitfunc():
2015 print "world"
2016 sys.exitfunc = exitfunc
2017 print "hello"
2018 sys.exit(1)
2019 print "there" # never printed # 不会被 print
2020 hello
2021 world
2022 在 Python 2.0 以后, 你可以使用 atexit 模块来注册多个退出处理函数.
2023 1.14. atexit 模块
2024 (用于2.0 版本及以上) atexit 模块允许你注册一个或多个终止函数(暂且这么
2025 叫), 这些函数将在解释器终止前被自动调用.
2026 调用 register 函数, 便可以将函数注册为终止函数, 如 Example 1-78 所示.
2027 你也可以添加更多的参数, 这些将作为 exit 函数的参数传递.
2028 1.14.0.1. Example 1-78. 使用 atexit 模块
2029 File: atexit-example-1.py
2030 import atexit
2031 def exit(*args):
2032 print "exit", args
2033 # register two exit handler
2034 atexit.register(exit)
2035 atexit.register(exit, 1)
2036 atexit.register(exit, "hello", "world")
2037 exit ('hello', 'world')
2038 exit (1,)
2039 exit ()
2040 该模块其实是一个对 sys.exitfunc 钩子( hook )的简单封装.
2041 1.15. time 模块
2042 time 模块提供了一些处理日期和一天内时间的函数. 它是建立在 C 运行时库
2043 的简单封装.
2044 给定的日期和时间可以被表示为浮点型(从参考时间, 通常是 1970.1.1 到现在
2045 经过的秒数. 即 Unix 格式), 或者一个表示时间的 struct (类元组).
2046 1.15.1. 获得当前时间
2047 Example 1-79 展示了如何使用 time 模块获取当前时间.
2048 1.15.1.1. Example 1-79. 使用 time 模块获取当前时间
2049 File: time-example-1.py
2050 import time
2051 now = time.time()
2052 print now, "seconds since", time.gmtime(0)[:6]
2053 print
2054 print "or in other words:"
2055 print "- local time:", time.localtime(now)
2056 print "- utc:", time.gmtime(now)
2057 937758359.77 seconds since (1970, 1, 1, 0, 0, 0)
2058 or in other words:
2059 - local time: (1999, 9, 19, 18, 25, 59, 6, 262, 1)
2060 - utc: (1999, 9, 19, 16, 25, 59, 6, 262, 0)
2061 localtime 和 gmtime 返回的类元组包括年, 月, 日, 时, 分, 秒, 星期, 一
2062 年的第几天, 日光标志. 其中年是一个四位数(在有千年虫问题的平台上另有规
2063 定, 但还是四位数), 星期从星期一(数字 0 代表)开始, 1 月1 日是一年的第一
2064 天.
2065 1.15.2. 将时间值转换为字符串
2066 你可以使用标准的格式化字符串把时间对象转换为字符串, 不过 time 模块已
2067 经提供了许多标准转换函数, 如 Example 1-80 所示.
2068 1.15.2.1. Example 1-80. 使用 time 模块格式化时间输出
2069 File: time-example-2.py
2070 import time
2071 now = time.localtime(time.time())
2072 print time.asctime(now)
2073 print time.strftime("%y/%m/%d %H:%M", now)
2074 print time.strftime("%a %b %d", now)
2075 print time.strftime("%c", now)
2076 print time.strftime("%I %p", now)
2077 print time.strftime("%Y-%m-%d %H:%M:%S %Z", now)
2078 # do it by hand...
2079 year, month, day, hour, minute, second, weekday, yearday, daylight = now
2080 print "%04d-%02d-%02d" % (year, month, day)
2081 print "%02d:%02d:%02d" % (hour, minute, second)
2082 print ("MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN")[weekday], yearday
2083 Sun Oct 10 21:39:24 1999
2084 99/10/10 21:39
2085 Sun Oct 10
2086 Sun Oct 10 21:39:24 1999
2087 09 PM
2088 1999-10-10 21:39:24 CEST
2089 1999-10-10
2090 21:39:24
2091 SUN 283
2092 1.15.3. 将字符串转换为时间对象
2093 在一些平台上, time 模块包含了 strptime 函数, 它的作用与 strftime 相反.
2094 给定一个字符串和模式, 它返回相应的时间对象, 如 Example 1-81 所示.
2095 1.15.3.1. Example 1-81. 使用 time.strptime 函数解析时间
2096 File: time-example-6.py
2097 import time
2098 # make sure we have a strptime function!
2099 # 确认有函数 strptime
2100 try:
2101 strptime = time.strptime
2102 except AttributeError:
2103 from strptime import strptime
2104 print strptime("31 Nov 00", "%d %b %y")
2105 print strptime("1 Jan 70 1:30pm", "%d %b %y %I:%M%p")
2106 只有在系统的 C 库提供了相应的函数的时候, time.strptime 函数才可以使用.
2107 对于没有提供标准实现的平台, Example 1-82 提供了一个不完全的实现.
2108 1.15.3.2. Example 1-82. strptime 实现
2109 File: strptime.py
2110 import re
2111 import string
2112 MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
2113 "Sep", "Oct", "Nov", "Dec"]
2114 SPEC = {
2115 # map formatting code to a regular expression fragment
2116 "%a": "(?P<weekday>[a-z]+)",
2117 "%A": "(?P<weekday>[a-z]+)",
2118 "%b": "(?P<month>[a-z]+)",
2119 "%B": "(?P<month>[a-z]+)",
2120 "%C": "(?P<century>\d\d?)",
2121 "%d": "(?P<day>\d\d?)",
2122 "%D": "(?P<month>\d\d?)/(?P<day>\d\d?)/(?P<year>\d\d)",
2123 "%e": "(?P<day>\d\d?)",
2124 "%h": "(?P<month>[a-z]+)",
2125 "%H": "(?P<hour>\d\d?)",
2126 "%I": "(?P<hour12>\d\d?)",
2127 "%j": "(?P<yearday>\d\d?\d?)",
2128 "%m": "(?P<month>\d\d?)",
2129 "%M": "(?P<minute>\d\d?)",
2130 "%p": "(?P<ampm12>am|pm)",
2131 "%R": "(?P<hour>\d\d?):(?P<minute>\d\d?)",
2132 "%S": "(?P<second>\d\d?)",
2133 "%T": "(?P<hour>\d\d?):(?P<minute>\d\d?):(?P<second>\d\d?)",
2134 "%U": "(?P<week>\d\d)",
2135 "%w": "(?P<weekday>\d)",
2136 "%W": "(?P<weekday>\d\d)",
2137 "%y": "(?P<year>\d\d)",
2138 "%Y": "(?P<year>\d\d\d\d)",
2139 "%%": "%"
2140 }
2141 class TimeParser:
2142 def _ _init_ _(self, format):
2143 # convert strptime format string to regular expression
2144 format = string.join(re.split("(?:\s|%t|%n)+", format))
2145 pattern = []
2146 try:
2147 for spec in re.findall("%\w|%%|.", format):
2148 if spec[0] == "%":
2149 spec = SPEC[spec]
2150 pattern.append(spec)
2151 except KeyError:
2152 raise ValueError, "unknown specificer: %s" % spec
2153 self.pattern = re.compile("(?i)" + string.join(pattern, ""))
2154 def match(self, daytime):
2155 # match time string
2156 match = self.pattern.match(daytime)
2157 if not match:
2158 raise ValueError, "format mismatch"
2159 get = match.groupdict().get
2160 tm = [0] * 9
2161 # extract date elements
2162 y = get("year")
2163 if y:
2164 y = int(y)
2165 if y < 68:
2166 y = 2000 + y
2167 elif y < 100:
2168 y = 1900 + y
2169 tm[0] = y
2170 m = get("month")
2171 if m:
2172 if m in MONTHS:
2173 m = MONTHS.index(m) + 1
2174 tm[1] = int(m)
2175 d = get("day")
2176 if d: tm[2] = int(d)
2177 # extract time elements
2178 h = get("hour")
2179 if h:
2180 tm[3] = int(h)
2181 else:
2182 h = get("hour12")
2183 if h:
2184 h = int(h)
2185 if string.lower(get("ampm12", "")) == "pm":
2186 h = h + 12
2187 tm[3] = h
2188 m = get("minute")
2189 if m: tm[4] = int(m)
2190 s = get("second")
2191 if s: tm[5] = int(s)
2192 # ignore weekday/yearday for now
2193 return tuple(tm)
2194 def strptime(string, format="%a %b %d %H:%M:%S %Y"):
2195 return TimeParser(format).match(string)
2196 if _ _name_ _ == "_ _main_ _":
2197 # try it out
2198 import time
2199 print strptime("2000-12-20 01:02:03", "%Y-%m-%d %H:%M:%S")
2200 print strptime(time.ctime(time.time()))
2201 (2000, 12, 20, 1, 2, 3, 0, 0, 0)
2202 (2000, 11, 15, 12, 30, 45, 0, 0, 0)
2203 1.15.4. 转换时间值
2204 将时间元组转换回时间值非常简单, 至少我们谈论的当地时间 (local time)
2205 如此. 只要把时间元组传递给 mktime 函数, 如 Example 1-83 所示.
2206 1.15.4.1. Example 1-83. 使用 time 模块将本地时间元组转换为时间值(整
2207 数)
2208 File: time-example-3.py
2209 import time
2210 t0 = time.time()
2211 tm = time.localtime(t0)
2212 print tm
2213 print t0
2214 print time.mktime(tm)
2215 (1999, 9, 9, 0, 11, 8, 3, 252, 1)
2216 936828668.16
2217 936828668.0
2218 但是, 1.5.2 版本的标准库没有提供能将 UTC 时间 (Universal Time,
2219 Coordinated: 特林威治标准时间)转换为时间值的函数 ( Python 和对应底层
2220 C 库都没有提供). Example 1-84 提供了该函数的一个 Python 实现, 称为
2221 timegm .
2222 1.15.4.2. Example 1-84. 将 UTC 时间元组转换为时间值(整数)
2223 File: time-example-4.py
2224 import time
2225 def _d(y, m, d, days=(0,31,59,90,120,151,181,212,243,273,304,334,365)):
2226 # map a date to the number of days from a reference point
2227 return (((y - 1901)*1461)/4 + days[m-1] + d +
2228 ((m > 2 and not y % 4 and (y % 100 or not y % 400)) and 1))
2229 def timegm(tm, epoch=_d(1970,1,1)):
2230 year, month, day, h, m, s = tm[:6]
2231 assert year >= 1970
2232 assert 1 <= month <= 12
2233 return (_d(year, month, day) - epoch)*86400 + h*3600 + m*60 + s
2234 t0 = time.time()
2235 tm = time.gmtime(t0)
2236 print tm
2237 print t0
2238 print timegm(tm)
2239 (1999, 9, 8, 22, 12, 12, 2, 251, 0)
2240 936828732.48
2241 936828732
2242 从 1.6 版本开始, calendar 模块提供了一个类似的函数 calendar.timegm .
2243 1.15.5. Timing 相关
2244 time 模块可以计算 Python 程序的执行时间, 如 Example 1-85 所示. 你可以
2245 测量 "wall time" (real world time), 或是"进程时间" (消耗的 CPU 时间).
2246 1.15.5.1. Example 1-85. 使用 time 模块评价算法
2247 File: time-example-5.py
2248 import time
2249 def procedure():
2250 time.sleep(2.5)
2251 # measure process time
2252 t0 = time.clock()
2253 procedure()
2254 print time.clock() - t0, "seconds process time"
2255 # measure wall time
2256 t0 = time.time()
2257 procedure()
2258 print time.time() - t0, "seconds wall time"
2259 0.0 seconds process time
2260 2.50903499126 seconds wall time
2261 并不是所有的系统都能测量真实的进程时间. 一些系统中(包括 Windows ),
2262 clock 函数通常测量从程序启动到测量时的 wall time.
2263 进程时间的精度受限制. 在一些系统中, 它超过 30 分钟后进程会被清理. (原
2264 文: On many systems, it wraps around after just over 30 minutes.)
2265 另参见 timing 模块( Windows 下的朋友不用忙活了,没有地~), 它可以测量两
2266 个事件之间的 wall time.
2267 1.16. types 模块
2268 types 模块包含了标准解释器定义的所有类型的类型对象, 如 Example 1-86
2269 所示. 同一类型的所有对象共享一个类型对象. 你可以使用 is 来检查一个对
2270 象是不是属于某个给定类型.
2271 1.16.0.1. Example 1-86. 使用 types 模块
2272 File: types-example-1.py
2273 import types
2274 def check(object):
2275 print object,
2276 if type(object) is types.IntType:
2277 print "INTEGER",
2278 if type(object) is types.FloatType:
2279 print "FLOAT",
2280 if type(object) is types.StringType:
2281 print "STRING",
2282 if type(object) is types.ClassType:
2283 print "CLASS",
2284 if type(object) is types.InstanceType:
2285 print "INSTANCE",
2286 print
2287 check(0)
2288 check(0.0)
2289 check("0")
2290 class A:
2291 pass
2292 class B:
2293 pass
2294 check(A)
2295 check(B)
2296 a = A()
2297 b = B()
2298 check(a)
2299 check(b)
2300 0 INTEGER
2301 0.0 FLOAT
2302 0 STRING
2303 A CLASS
2304 B CLASS
2305 <A instance at 796960> INSTANCE
2306 <B instance at 796990> INSTANCE
2307 注意所有的类都具有相同的类型, 所有的实例也是一样. 要测试一个类或者实
2308 例所属的类, 可以使用内建的 issubclass 和 isinstance 函数.
2309 types 模块在第一次引入的时候会破坏当前的异常状态. 也就是说, 不要在异
2310 常处理语句块中导入该模块 (或其他会导入它的模块 ) .
2311 1.17. gc 模块
2312 (可选, 2.0 及以后版本) gc 模块提供了到内建循环垃圾收集器的接口.
2313 Python 使用引用记数来跟踪什么时候销毁一个对象; 一个对象的最后一个引用
2314 一旦消失, 这个对象就会被销毁.
2315 从 2.0 版开始, Python 还提供了一个循环垃圾收集器, 它每隔一段时间执行.
2316 这个收集器查找指向自身的数据结构, 并尝试破坏循环. 如 Example 1-87 所
2317 示.
2318 你可以使用 gc.collect 函数来强制完整收集. 这个函数将返回收集器销毁的
2319 对象的数量.
2320 1.17.0.1. Example 1-87. 使用 gc 模块收集循环引用垃圾
2321 File: gc-example-1.py
2322 import gc
2323 # create a simple object that links to itself
2324 class Node:
2325 def _ _init_ _(self, name):
2326 self.name = name
2327 self.parent = None
2328 self.children = []
2329 def addchild(self, node):
2330 node.parent = self
2331 self.children.append(node)
2332 def _ _repr_ _(self):
2333 return "<Node %s at %x>" % (repr(self.name), id(self))
2334 # set up a self-referencing structure
2335 root = Node("monty")
2336 root.addchild(Node("eric"))
2337 root.addchild(Node("john"))
2338 root.addchild(Node("michael"))
2339 # remove our only reference
2340 del root
2341 print gc.collect(), "unreachable objects"
2342 print gc.collect(), "unreachable objects"
2343 12 unreachable objects
2344 0 unreachable objects
2345 如果你确定你的程序不会创建自引用的数据结构, 你可以使用 gc.disable 函
2346 数禁用垃圾收集, 调用这个函数以后, Python 的工作方式将与 1.5.2 或更早
2347 的版本相同.
1 2. 更多标准模块python标准库实例-2标准模块
2 o 2.1. 概览
3 o 2.2. fileinput 模块
4 o 2.3. shutil 模块
5 o 2.4. tempfile 模块
6 o 2.5. StringIO 模块
7 o 2.6. cStringIO 模块
8 o 2.7. mmap 模块
9 o 2.8. UserDict 模块
10 o 2.9. UserList 模块
11 o 2.10. UserString 模块
12 o 2.11. traceback 模块
13 o 2.12. errno 模块
14 o 2.13. getopt 模块
15 o 2.14. getpass 模块
16 o 2.15. glob 模块
17 o 2.16. fnmatch 模块
18 o 2.17. random 模块
19 o 2.18. whrandom 模块
20 o 2.19. md5 模块
21 o 2.20. sha 模块
22 o 2.21. crypt 模块
23 o 2.22. rotor 模块
24 o 2.23. zlib 模块
25 o 2.24. code 模块
26
27
28
29 2. 更多标准模块
30 "Now, imagine that your friend kept complaining that she didn't want to
31 visit you since she found it too hard to climb up the drain pipe, and you
32 kept telling her to use the friggin' stairs like everyone else..."
33 - eff-bot, June 1998
34 2.1. 概览
35 本章叙述了许多在 Python 程序中广泛使用的模块. 当然, 在大型的 Python
36 程序中不使用这些模块也是可以的, 但如果使用会节省你不少时间.
37 2.1.1. 文件与流
38 fileinput 模块可以让你更简单地向不同的文件写入内容. 该模块提供了一个
39 简单的封装类, 一个简单的 for-in 语句就可以循环得到一个或多个文本文件
40 的内容.
41 StringIO 模块 (以及 cStringIO 模块, 作为一个的变种) 实现了一个工作在
42 内存的文件对象. 你可以在很多地方用 StringIO 对象替换普通的文件对象.
43 2.1.2. 类型封装
44 UserDict , UserList , 以及 UserString 是对应内建类型的顶层简单封装. 和
45 内建类型不同的是, 这些封装是可以被继承的. 这在你需要一个和内建类型行
46 为相似但由额外新方法的类的时候很有用.
47 2.1.3. 随机数字
48 random 模块提供了一些不同的随机数字生成器. whrandom 模块与此相似, 但
49 允许你创建多个生成器对象.
50 [!Feather 注: whrandom 在版本 2.1 时声明不支持. 请使用 random 替代.]
51 2.1.4. 加密算法
52 md5 和 sha 模块用于计算密写的信息标记( cryptographically strong
53 message signatures , 所谓的 "message digests", 信息摘要).
54 crypt 模块实现了 DES 样式的单向加密. 该模块只在 Unix 系统下可用.
55 rotor 模块提供了简单的双向加密. 版本 2.4 以后的朋友可以不用忙活了.
56 [!Feather 注: 它在版本 2.3 时申明不支持, 因为它的加密运算不安全.]
57 2.2. fileinput 模块
58 fileinput 模块允许你循环一个或多个文本文件的内容, 如 Example 2-1 所
59 示.
60 2.2.0.1. Example 2-1. 使用 fileinput 模块循环一个文本文件
61 File: fileinput-example-1.py
62 import fileinput
63 import sys
64 for line in fileinput.input("samples/sample.txt"):
65 sys.stdout.write("-> ")
66 sys.stdout.write(line)
67 -> We will perhaps eventually be writing only small
68 -> modules which are identified by name as they are
69 -> used to build larger ones, so that devices like
70 -> indentation, rather than delimiters, might become
71 -> feasible for expressing local structure in the
72 -> source language.
73 -> -- Donald E. Knuth, December 1974
74 你也可以使用 fileinput 模块获得当前行的元信息 (meta information). 其
75 中包括 isfirstline , filename , lineno , 如 Example 2-2 所示.
76 2.2.0.2. Example 2-2. 使用 fileinput 模块处理多个文本文件
77 File: fileinput-example-2.py
78 import fileinput
79 import glob
80 import string, sys
81 for line in fileinput.input(glob.glob("samples/*.txt")):
82 if fileinput.isfirstline(): # first in a file?
83 sys.stderr.write("-- reading %s --\n" % fileinput.filename())
84 sys.stdout.write(str(fileinput.lineno()) + " " +
85 string.upper(line))
86 -- reading samples\sample.txt --
87 1 WE WILL PERHAPS EVENTUALLY BE WRITING ONLY SMALL
88 2 MODULES WHICH ARE IDENTIFIED BY NAME AS THEY ARE
89 3 USED TO BUILD LARGER ONES, SO THAT DEVICES LIKE
90 4 INDENTATION, RATHER THAN DELIMITERS, MIGHT BECOME
91 5 FEASIBLE FOR EXPRESSING LOCAL STRUCTURE IN THE
92 6 SOURCE LANGUAGE.
93 7 -- DONALD E. KNUTH, DECEMBER 1974
94 文本文件的替换操作很简单. 只需要把 inplace 关键字参数设置为 1 , 传递
95 给 input 函数, 该模块会帮你做好一切. Example 2-3 展示了这些.
96 2.2.0.3. Example 2-3. 使用 fileinput 模块将 CRLF 改为 LF
97 File: fileinput-example-3.py
98 import fileinput, sys
99 for line in fileinput.input(inplace=1):
100 # convert Windows/DOS text files to Unix files
101 if line[-2:] == "\r\n":
102 line = line[:-2] + "\n"
103 sys.stdout.write(line)
104 2.3. shutil 模块
105 shutil 实用模块包含了一些用于复制文件和文件夹的函数. Example 2-4 中使
106 用的 copy 函数使用和 Unix 下 cp 命令基本相同的方式复制一个文件.
107 2.3.0.1. Example 2-4. 使用 shutil 复制文件
108 File: shutil-example-1.py
109 import shutil
110 import os
111 for file in os.listdir("."):
112 if os.path.splitext(file)[1] == ".py":
113 print file
114 shutil.copy(file, os.path.join("backup", file))
115 aifc-example-1.py
116 anydbm-example-1.py
117 array-example-1.py
118 ...
119 copytree 函数用于复制整个目录树 (与 cp -r 相同), 而 rmtree 函数用于删
120 除整个目录树 (与 rm -r ). 如 Example 2-5 所示.
121 2.3.0.2. Example 2-5. 使用 shutil 模块复制/删除目录树
122 File: shutil-example-2.py
123 import shutil
124 import os
125 SOURCE = "samples"
126 BACKUP = "samples-bak"
127 # create a backup directory
128 shutil.copytree(SOURCE, BACKUP)
129 print os.listdir(BACKUP)
130 # remove it
131 shutil.rmtree(BACKUP)
132 print os.listdir(BACKUP)
133 ['sample.wav', 'sample.jpg', 'sample.au', 'sample.msg', 'sample.tgz',
134 ...
135 Traceback (most recent call last):
136 File "shutil-example-2.py", line 17, in ?
137 print os.listdir(BACKUP)
138 os.error: No such file or directory
139 2.4. tempfile 模块
140 Example 2-6 中展示的 tempfile 模块允许你快速地创建名称唯一的临时文件
141 供使用.
142 2.4.0.1. Example 2-6. 使用 tempfile 模块创建临时文件
143 File: tempfile-example-1.py
144 import tempfile
145 import os
146 tempfile = tempfile.mktemp()
147 print "tempfile", "=>", tempfile
148 file = open(tempfile, "w+b")
149 file.write("*" * 1000)
150 file.seek(0)
151 print len(file.read()), "bytes"
152 file.close()
153 try:
154 # must remove file when done
155 os.remove(tempfile)
156 except OSError:
157 pass
158 tempfile => C:\TEMP\~160-1
159 1000 bytes
160 TemporaryFile 函数会自动挑选合适的文件名, 并打开文件, 如 Example 2-7
161 所示. 而且它会确保该文件在关闭的时候会被删除. (在 Unix 下, 你可以删除
162 一个已打开的文件, 这时文件关闭时它会被自动删除. 在其他平台上, 这通过
163 一个特殊的封装类实现.)
164 2.4.0.2. Example 2-7. 使用 tempfile 模块打开临时文件
165 File: tempfile-example-2.py
166 import tempfile
167 file = tempfile.TemporaryFile()
168 for i in range(100):
169 file.write("*" * 100)
170 file.close() # removes the file!
171 2.5. StringIO 模块
172 Example 2-8 展示了 StringIO 模块的使用. 它实现了一个工作在内存的文件
173 对象 (内存文件). 在大多需要标准文件对象的地方都可以使用它来替换.
174 2.5.0.1. Example 2-8. 使用 StringIO 模块从内存文件读入内容
175 File: stringio-example-1.py
176 import StringIO
177 MESSAGE = "That man is depriving a village somewhere of a computer
178 scientist."
179 file = StringIO.StringIO(MESSAGE)
180 print file.read()
181 That man is depriving a village somewhere of a computer scientist.
182 StringIO 类实现了内建文件对象的所有方法, 此外还有 getvalue 方法用来返
183 回它内部的字符串值. Example 2-9 展示了这个方法.
184 2.5.0.2. Example 2-9. 使用 StringIO 模块向内存文件写入内容
185 File: stringio-example-2.py
186 import StringIO
187 file = StringIO.StringIO()
188 file.write("This man is no ordinary man. ")
189 file.write("This is Mr. F. G. Superman.")
190 print file.getvalue()
191 This man is no ordinary man. This is Mr. F. G. Superman.
192 StringIO 可以用于重新定向 Python 解释器的输出, 如 Example 2-10 所示.
193 2.5.0.3. Example 2-10. 使用 StringIO 模块捕获输出
194 File: stringio-example-3.py
195 import StringIO
196 import string, sys
197 stdout = sys.stdout
198 sys.stdout = file = StringIO.StringIO()
199 print """
200 According to Gbaya folktales, trickery and guile
201 are the best ways to defeat the python, king of
202 snakes, which was hatched from a dragon at the
203 world's start. -- National Geographic, May 1997
204 """
205 sys.stdout = stdout
206 print string.upper(file.getvalue())
207 ACCORDING TO GBAYA FOLKTALES, TRICKERY AND GUILE
208 ARE THE BEST WAYS TO DEFEAT THE PYTHON, KING OF
209 SNAKES, WHICH WAS HATCHED FROM A DRAGON AT THE
210 WORLD'S START. -- NATIONAL GEOGRAPHIC, MAY 1997
211 2.6. cStringIO 模块
212 cStringIO 是一个可选的模块, 是 StringIO 的更快速实现. 它的工作方式和
213 StringIO 基本相同, 但是它不可以被继承. Example 2-11 展示了 cStringIO
214 的用法, 另参考前一节.
215 2.6.0.1. Example 2-11. 使用 cStringIO 模块
216 File: cstringio-example-1.py
217 import cStringIO
218 MESSAGE = "That man is depriving a village somewhere of a computer
219 scientist."
220 file = cStringIO.StringIO(MESSAGE)
221 print file.read()
222 That man is depriving a village somewhere of a computer scientist.
223 为了让你的代码尽可能快, 但同时保证兼容低版本的 Python ,你可以使用一个
224 小技巧在 cStringIO 不可用时启用 StringIO 模块, 如 Example 2-12 所示.
225 2.6.0.2. Example 2-12. 后退至 StringIO
226 File: cstringio-example-2.py
227 try:
228 import cStringIO
229 StringIO = cStringIO
230 except ImportError:
231 import StringIO
232 print StringIO
233 <module 'StringIO' (built-in)>
234 2.7. mmap 模块
235 (2.0 新增) mmap 模块提供了操作系统内存映射函数的接口, 如 Example 2-13
236 所示. 映射区域的行为和字符串对象类似, 但数据是直接从文件读取的.
237 2.7.0.1. Example 2-13. 使用 mmap 模块
238 File: mmap-example-1.py
239 import mmap
240 import os
241 filename = "samples/sample.txt"
242 file = open(filename, "r+")
243 size = os.path.getsize(filename)
244 data = mmap.mmap(file.fileno(), size)
245 # basics
246 print data
247 print len(data), size
248 # use slicing to read from the file
249 # 使用切片操作读取文件
250 print repr(data[:10]), repr(data[:10])
251 # or use the standard file interface
252 # 或使用标准的文件接口
253 print repr(data.read(10)), repr(data.read(10))
254 <mmap object at 008A2A10>
255 302 302
256 'We will pe' 'We will pe'
257 'We will pe' 'rhaps even'
258 在 Windows 下, 这个文件必须以既可读又可写的模式打开( `r+` , `w+` , 或
259 `a+` ), 否则 mmap 调用会失败.
260 [!Feather 注: 经本人测试, a+ 模式是完全可以的, 原文只有 r+ 和 w+]
261 Example 2-14 展示了内存映射区域的使用, 在很多地方它都可以替换普通字符
262 串使用, 包括正则表达式和其他字符串操作.
263 2.7.0.2. Example 2-14. 对映射区域使用字符串方法和正则表达式
264 File: mmap-example-2.py
265 import mmap
266 import os, string, re
267 def mapfile(filename):
268 file = open(filename, "r+")
269 size = os.path.getsize(filename)
270 return mmap.mmap(file.fileno(), size)
271 data = mapfile("samples/sample.txt")
272 # search
273 index = data.find("small")
274 print index, repr(data[index-5:index+15])
275 # regular expressions work too!
276 m = re.search("small", data)
277 print m.start(), m.group()
278 43 'only small\015\012modules '
279 43 small
280 2.8. UserDict 模块
281 UserDict 模块包含了一个可继承的字典类 (事实上是对内建字典类型的
282 Python 封装).
283 Example 2-15 展示了一个增强的字典类, 允许对字典使用 "加/+" 操作并提供
284 了接受关键字参数的构造函数.
285 2.8.0.1. Example 2-15. 使用 UserDict 模块
286 File: userdict-example-1.py
287 import UserDict
288 class FancyDict(UserDict.UserDict):
289 def _ _init_ _(self, data = {}, **kw):
290 UserDict.UserDict._ _init_ _(self)
291 self.update(data)
292 self.update(kw)
293 def _ _add_ _(self, other):
294 dict = FancyDict(self.data)
295 dict.update(b)
296 return dict
297 a = FancyDict(a = 1)
298 b = FancyDict(b = 2)
299 print a + b
300 {'b': 2, 'a': 1}
301 2.9. UserList 模块
302 UserList 模块包含了一个可继承的列表类 (事实上是对内建列表类型的
303 Python 封装).
304 在 Example 2-16 中, AutoList 实例类似一个普通的列表对象, 但它允许你通
305 过赋值为列表添加项目.
306 2.9.0.1. Example 2-16. 使用 UserList 模块
307 File: userlist-example-1.py
308 import UserList
309 class AutoList(UserList.UserList):
310 def _ _setitem_ _(self, i, item):
311 if i == len(self.data):
312 self.data.append(item)
313 else:
314 self.data[i] = item
315 list = AutoList()
316 for i in range(10):
317 list[i] = i
318 print list
319 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
320 2.10. UserString 模块
321 (2.0 新增) UserString 模块包含两个类, UserString 和 MutableString . 前
322 者是对标准字符串类型的封装, 后者是一个变种, 允许你修改特定位置的字符
323 (联想下列表就知道了).
324 注意 MutableString 并不是效率很好, 许多操作是通过切片和字符串连接实现
325 的. 如果性能很对你的脚本来说重要的话, 你最好使用字符串片断的列表或者
326 array 模块. Example 2-17 展示了 UserString 模块.
327 2.10.0.1. Example 2-17. 使用 UserString 模块
328 File: userstring-example-1.py
329 import UserString
330 class MyString(UserString.MutableString):
331 def append(self, s):
332 self.data = self.data + s
333 def insert(self, index, s):
334 self.data = self.data[index:] + s + self.data[index:]
335 def remove(self, s):
336 self.data = self.data.replace(s, "")
337 file = open("samples/book.txt")
338 text = file.read()
339 file.close()
340 book = MyString(text)
341 for bird in ["gannet", "robin", "nuthatch"]:
342 book.remove(bird)
343 print book
344 ...
345 C: The one without the !
346 P: The one without the -!!! They've ALL got the !! It's a
347 Standard British Bird, the , it's in all the books!!!
348 ...
349 2.11. traceback 模块
350 Example 2-18 展示了 traceback 模块允许你在程序里打印异常的跟踪返回
351 (Traceback)信息, 类似未捕获异常时解释器所做的. 如 Example 2-18 所示.
352 2.11.0.1. Example 2-18. 使用 traceback 模块打印跟踪返回信息
353 File: traceback-example-1.py
354 # note! importing the traceback module messes up the
355 # exception state, so you better do that here and not
356 # in the exception handler
357 # 注意! 导入 traceback 会清理掉异常状态, 所以
358 # 最好别在异常处理代码中导入该模块
359 import traceback
360 try:
361 raise SyntaxError, "example"
362 except:
363 traceback.print_exc()
364 Traceback (innermost last):
365 File "traceback-example-1.py", line 7, in ?
366 SyntaxError: example
367 Example 2-19 使用 StringIO 模块将跟踪返回信息放在字符串中.
368 2.11.0.2. Example 2-19. 使用 traceback 模块将跟踪返回信息复制到字符串
369 File: traceback-example-2.py
370 import traceback
371 import StringIO
372 try:
373 raise IOError, "an i/o error occurred"
374 except:
375 fp = StringIO.StringIO()
376 traceback.print_exc(file=fp)
377 message = fp.getvalue()
378 print "failure! the error was:", repr(message)
379 failure! the error was: 'Traceback (innermost last):\012 File
380 "traceback-example-2.py", line 5, in ?\012IOError: an i/o error
381 occurred\012'
382 你可以使用 extract_tb 函数格式化跟踪返回信息, 得到包含错误信息的列表,
383 如 Example 2-20 所示.
384 2.11.0.3. Example 2-20. 使用 traceback Module 模块编码 Traceback 对象
385 File: traceback-example-3.py
386 import traceback
387 import sys
388 def function():
389 raise IOError, "an i/o error occurred"
390 try:
391 function()
392 except:
393 info = sys.exc_info()
394 for file, lineno, function, text in traceback.extract_tb(info[2]):
395 print file, "line", lineno, "in", function
396 print "=>", repr(text)
397 print "** %s: %s" % info[:2]
398 traceback-example-3.py line 8 in ?
399 => 'function()'
400 traceback-example-3.py line 5 in function
401 => 'raise IOError, "an i/o error occurred"'
402 ** exceptions.IOError: an i/o error occurred
403 2.12. errno 模块
404 errno 模块定义了许多的符号错误码, 比如 ENOENT ("没有该目录入口") 以及
405 EPERM ("权限被拒绝"). 它还提供了一个映射到对应平台数字错误代码的字典.
406 Example 2-21 展示了如何使用 errno 模块.
407 在大多情况下, IOError 异常会提供一个二元元组, 包含对应数值错误代码和
408 一个说明字符串. 如果你需要区分不同的错误代码, 那么最好在可能的地方使
409 用符号名称.
410 2.12.0.1. Example 2-21. 使用 errno 模块
411 File: errno-example-1.py
412 import errno
413 try:
414 fp = open("no.such.file")
415 except IOError, (error, message):
416 if error == errno.ENOENT:
417 print "no such file"
418 elif error == errno.EPERM:
419 print "permission denied"
420 else:
421 print message
422 no such file
423 Example 2-22 绕了些无用的弯子, 不过它很好地说明了如何使用 errorcode
424 字典把数字错误码映射到符号名称( symbolic name ).
425 2.12.0.2. Example 2-22. 使用 errorcode 字典
426 File: errno-example-2.py
427 import errno
428 try:
429 fp = open("no.such.file")
430 except IOError, (error, message):
431 print error, repr(message)
432 print errno.errorcode[error]
433 # 2 'No such file or directory'
434 # ENOENT
435 2.13. getopt 模块
436 getopt 模块包含用于抽出命令行选项和参数的函数, 它可以处理多种格式的选
437 项. 如 Example 2-23 所示.
438 其中第 2 个参数指定了允许的可缩写的选项. 选项名后的冒号(:) 意味这这个
439 选项必须有额外的参数.
440 2.13.0.1. Example 2-23. 使用 getopt 模块
441 File: getopt-example-1.py
442 import getopt
443 import sys
444 # simulate command-line invocation
445 # 模仿命令行参数
446 sys.argv = ["myscript.py", "-l", "-d", "directory", "filename"]
447 # process options
448 # 处理选项
449 opts, args = getopt.getopt(sys.argv[1:], "ld:")
450 long = 0
451 directory = None
452 for o, v in opts:
453 if o == "-l":
454 long = 1
455 elif o == "-d":
456 directory = v
457 print "long", "=", long
458 print "directory", "=", directory
459 print "arguments", "=", args
460 long = 1
461 directory = directory
462 arguments = ['filename']
463 为了让 getopt 查找长的选项, 如 Example 2-24 所示, 传递一个描述选项的
464 列表做为第 3 个参数. 如果一个选项名称以等号(=) 结尾, 那么它必须有一个
465 附加参数.
466 2.13.0.2. Example 2-24. 使用 getopt 模块处理长选项
467 File: getopt-example-2.py
468 import getopt
469 import sys
470 # simulate command-line invocation
471 # 模仿命令行参数
472 sys.argv = ["myscript.py", "--echo", "--printer", "lp01", "message"]
473 opts, args = getopt.getopt(sys.argv[1:], "ep:", ["echo", "printer="])
474 # process options
475 # 处理选项
476 echo = 0
477 printer = None
478 for o, v in opts:
479 if o in ("-e", "--echo"):
480 echo = 1
481 elif o in ("-p", "--printer"):
482 printer = v
483 print "echo", "=", echo
484 print "printer", "=", printer
485 print "arguments", "=", args
486 echo = 1
487 printer = lp01
488 arguments = ['message']
489 [!Feather 注: 我不知道大家明白没, 可以自己试下:
490 myscript.py -e -p lp01 message
491 myscript.py --echo --printer=lp01 message
492 ]
493 2.14. getpass 模块
494 getpass 模块提供了平台无关的在命令行下输入密码的方法. 如 Example 2-25
495 所示.
496 getpass(prompt) 会显示提示字符串, 关闭键盘的屏幕反馈, 然后读取密码.
497 如果提示参数省略, 那么它将打印出 "Password: ".
498 getuser() 获得当前用户名, 如果可能的话.
499 2.14.0.1. Example 2-25. 使用 getpass 模块
500 File: getpass-example-1.py
501 import getpass
502 usr = getpass.getuser()
503 pwd = getpass.getpass("enter password for user %s: " % usr)
504 print usr, pwd
505 enter password for user mulder:
506 mulder trustno1
507 2.15. glob 模块
508 glob 根据给定模式生成满足该模式的文件名列表, 和 Unix shell 相同.
509 这里的模式和正则表达式类似, 但更简单. 星号(* ) 匹配零个或更多个字符,
510 问号(? ) 匹配单个字符. 你也可以使用方括号来指定字符范围, 例如 [0-9]
511 代表一个数字. 其他所有字符都代表它们本身.
512 glob(pattern) 返回满足给定模式的所有文件的列表. Example 2-26 展示了它
513 的用法.
514 2.15.0.1. Example 2-26. 使用 glob 模块
515 File: glob-example-1.py
516 import glob
517 for file in glob.glob("samples/*.jpg"):
518 print file
519 samples/sample.jpg
520 注意这里的 glob 返回完整路径名, 这点和 os.listdir 函数不同. glob 事实
521 上使用了 fnmatch 模块来完成模式匹配.
522 2.16. fnmatch 模块
523 fnmatch 模块使用模式来匹配文件名. 如 Example 2-27 所示.
524 模式语法和 Unix shell 中所使用的相同. 星号(* ) 匹配零个或更多个字符,
525 问号(? ) 匹配单个字符. 你也可以使用方括号来指定字符范围, 例如 [0-9]
526 代表一个数字. 其他所有字符都匹配它们本身.
527 2.16.0.1. Example 2-27. 使用 fnmatch 模块匹配文件
528 File: fnmatch-example-1.py
529 import fnmatch
530 import os
531 for file in os.listdir("samples"):
532 if fnmatch.fnmatch(file, "*.jpg"):
533 print file
534 sample.jpg
535 Example 2-28 中的 translate 函数可以将一个文件匹配模式转换为正则表达
536 式.
537 2.16.0.2. Example 2-28. 使用 fnmatch 模块将模式转换为正则表达式
538 File: fnmatch-example-2.py
539 import fnmatch
540 import os, re
541 pattern = fnmatch.translate("*.jpg")
542 for file in os.listdir("samples"):
543 if re.match(pattern, file):
544 print file
545 print "(pattern was %s)" % pattern
546 sample.jpg
547 (pattern was .*\.jpg$)
548 glob 和 find 模块在内部使用 fnmatch 模块来实现.
549 2.17. random 模块
550 "Anyone who considers arithmetical methods of producing random digits is,
551 of course, in a state of sin."
552 - John von Neumann, 1951
553 random 模块包含许多随机数生成器.
554 基本随机数生成器(基于 Wichmann 和 Hill , 1982 的数学运算理论) 可以通过
555 很多方法访问, 如 Example 2-29 所示.
556 2.17.0.1. Example 2-29. 使用 random 模块获得随机数字
557 File: random-example-1.py
558 import random
559 for i in range(5):
560 # random float: 0.0 <= number < 1.0
561 print random.random(),
562 # random float: 10 <= number < 20
563 print random.uniform(10, 20),
564 # random integer: 100 <= number <= 1000
565 print random.randint(100, 1000),
566 # random integer: even numbers in 100 <= number < 1000
567 print random.randrange(100, 1000, 2)
568 0.946842713956 19.5910069381 709 172
569 0.573613195398 16.2758417025 407 120
570 0.363241598013 16.8079747714 916 580
571 0.602115173978 18.386796935 531 774
572 0.526767588533 18.0783794596 223 344
573 注意这里的 randint 函数可以返回上界, 而其他函数总是返回小于上界的值.
574 所有函数都有可能返回下界值.
575 Example 2-30 展示了 choice 函数, 它用来从一个序列里分拣出一个随机项目.
576 它可以用于列表, 元组, 以及其他序列(当然, 非空的).
577 2.17.0.2. Example 2-30. 使用 random 模块从序列取出随机项
578 File: random-example-2.py
579 import random
580 # random choice from a list
581 for i in range(5):
582 print random.choice([1, 2, 3, 5, 9])
583 2
584 3
585 1
586 9
587 1
588 在 2.0 及以后版本, shuffle 函数可以用于打乱一个列表的内容 (也就是生成
589 一个该列表的随机全排列). Example 2-31 展示了如何在旧版本中实现该函数.
590 2.17.0.3. Example 2-31. 使用 random 模块打乱一副牌
591 File: random-example-4.py
592 import random
593 try:
594 # available in 2.0 and later
595 shuffle = random.shuffle
596 except AttributeError:
597 def shuffle(x):
598 for i in xrange(len(x)-1, 0, -1):
599 # pick an element in x[:i+1] with which to exchange x[i]
600 j = int(random.random() * (i+1))
601 x[i], x[j] = x[j], x[i]
602 cards = range(52)
603 shuffle(cards)
604 myhand = cards[:5]
605 print myhand
606 [4, 8, 40, 12, 30]
607 random 模块也包含了非恒定分布的随机生成器函数. Example 2-32 使用了
608 gauss (高斯)函数来生成满足高斯分的布随机数字.
609 2.17.0.4. Example 2-32. 使用 random 模块生成高斯分布随机数
610 File: random-example-3.py
611 import random
612 histogram = [0] * 20
613 # calculate histogram for gaussian
614 # noise, using average=5, stddev=1
615 for i in range(1000):
616 i = int(random.gauss(5, 1) * 2)
617 histogram[i] = histogram[i] + 1
618 # print the histogram
619 m = max(histogram)
620 for v in histogram:
621 print "*" * (v * 50 / m)
622 ****
623 **********
624 *************************
625 ***********************************
626 ************************************************
627 **************************************************
628 *************************************
629 ***************************
630 *************
631 ***
632 *
633 你可以在 Python Library Reference 找到更多关于非恒定分布随机生成器函数
634 的信息.
635 标准库中提供的随机数生成器都是伪随机数生成器. 不过这对于很多目的来说
636 已经足够了, 比如模拟, 数值分析, 以及游戏. 可以确定的是它不适合密码学
637 用途.
638 2.18. whrandom 模块
639 这个模块早在 2.1 就被声明不赞成, 早废了. 请使用 random 代替.
640 - Feather
641 Example 2-33 展示了 whrandom , 它提供了一个伪随机数生成器. (基于
642 Wichmann 和 Hill, 1982 的数学运算理论). 除非你需要不共享状态的多个生
643 成器(如多线程程序), 请使用 random 模块代替.
644 2.18.0.1. Example 2-33. 使用 whrandom 模块
645 File: whrandom-example-1.py
646 import whrandom
647 # same as random
648 print whrandom.random()
649 print whrandom.choice([1, 2, 3, 5, 9])
650 print whrandom.uniform(10, 20)
651 print whrandom.randint(100, 1000)
652 0.113412062346
653 1
654 16.8778954689
655 799
656 Example 2-34 展示了如何使用 whrandom 类实例创建多个生成器.
657 2.18.0.2. Example 2-34. 使用 whrandom 模块创建多个随机生成器
658 File: whrandom-example-2.py
659 import whrandom
660 # initialize all generators with the same seed
661 rand1 = whrandom.whrandom(4,7,11)
662 rand2 = whrandom.whrandom(4,7,11)
663 rand3 = whrandom.whrandom(4,7,11)
664 for i in range(5):
665 print rand1.random(), rand2.random(), rand3.random()
666 0.123993532536 0.123993532536 0.123993532536
667 0.180951499518 0.180951499518 0.180951499518
668 0.291924111809 0.291924111809 0.291924111809
669 0.952048889363 0.952048889363 0.952048889363
670 0.969794283643 0.969794283643 0.969794283643
671 2.19. md5 模块
672 md5 (Message-Digest Algorithm 5)模块用于计算信息密文(信息摘要).
673 md5 算法计算一个强壮的128 位密文. 这意味着如果两个字符串是不同的, 那
674 么有极高可能它们的 md5 也不同. 也就是说, 给定一个 md5 密文, 那么几乎
675 没有可能再找到另个字符串的密文与此相同. Example 2-35 展示了如何使用
676 md5 模块.
677 2.19.0.1. Example 2-35. 使用 md5 模块
678 File: md5-example-1.py
679 import md5
680 hash = md5.new()
681 hash.update("spam, spam, and eggs")
682 print repr(hash.digest())
683 'L\005J\243\266\355\243u`\305r\203\267\020F\303'
684 注意这里的校验和是一个二进制字符串. Example 2-36 展示了如何获得一个十
685 六进制或 base64 编码的字符串.
686 2.19.0.2. Example 2-36. 使用 md5 模块获得十六进制或 base64 编码的 md5
687 值
688 File: md5-example-2.py
689 import md5
690 import string
691 import base64
692 hash = md5.new()
693 hash.update("spam, spam, and eggs")
694 value = hash.digest()
695 print hash.hexdigest()
696 # before 2.0, the above can be written as
697 # 在 2.0 前, 以上应该写做:
698 # print string.join(map(lambda v: "%02x" % ord(v), value), "")
699 print base64.encodestring(value)
700 4c054aa3b6eda37560c57283b71046c3
701 TAVKo7bto3VgxXKDtxBGww==
702 Example 2-37 展示了如何使用 md5 校验和来处理口令的发送与应答的验证(不
703 过我们将稍候讨论这里使用随机数字所带来的问题).
704 2.19.0.3. Example 2-37. 使用 md5 模块来处理口令的发送与应答的验证
705 File: md5-example-3.py
706 import md5
707 import string, random
708 def getchallenge():
709 # generate a 16-byte long random string. (note that the built-
710 # in pseudo-random generator uses a 24-bit seed, so this is not
711 # as good as it may seem...)
712 # 生成一个 16 字节长的随机字符串. 注意内建的伪随机生成器
713 # 使用的是 24 位的种子(seed), 所以这里这样用并不好..
714 challenge = map(lambda i: chr(random.randint(0, 255)), range(16))
715 return string.join(challenge, "")
716 def getresponse(password, challenge):
717 # calculate combined digest for password and challenge
718 # 计算密码和质询(challenge)的联合密文
719 m = md5.new()
720 m.update(password)
721 m.update(challenge)
722 return m.digest()
723 #
724 # server/client communication
725 # 服务器/客户端通讯
726 # 1. client connects. server issues challenge.
727 # 1. 客户端连接, 服务器发布质询(challenge)
728 print "client:", "connect"
729 challenge = getchallenge()
730 print "server:", repr(challenge)
731 # 2. client combines password and challenge, and calculates
732 # the response.
733 # 2. 客户端计算密码和质询(challenge)的组合后的密文
734 client_response = getresponse("trustno1", challenge)
735 print "client:", repr(client_response)
736 # 3. server does the same, and compares the result with the
737 # client response. the result is a safe login in which the
738 # password is never sent across the communication channel.
739 # 3. 服务器做同样的事, 然后比较结果与客户端的返回,
740 # 判断是否允许用户登陆. 这样做密码没有在通讯中明文传输.
741 server_response = getresponse("trustno1", challenge)
742 if server_response == client_response:
743 print "server:", "login ok"
744 client: connect
745 server: '\334\352\227Z#\272\273\212KG\330\265\032>\311o'
746 client: "l'\305\240-x\245\237\035\225A\254\233\337\225\001"
747 server: login ok
748 Example 2-38 提供了 md5 的一个变种, 你可以通过标记信息来判断它是否在
749 网络传输过程中被修改(丢失).
750 2.19.0.4. Example 2-38. 使用 md5 模块检查数据完整性
751 File: md5-example-4.py
752 import md5
753 import array
754 class HMAC_MD5:
755 # keyed md5 message authentication
756 def _ _init_ _(self, key):
757 if len(key) > 64:
758 key = md5.new(key).digest()
759 ipad = array.array("B", [0x36] * 64)
760 opad = array.array("B", [0x5C] * 64)
761 for i in range(len(key)):
762 ipad[i] = ipad[i] ^ ord(key[i])
763 opad[i] = opad[i] ^ ord(key[i])
764 self.ipad = md5.md5(ipad.tostring())
765 self.opad = md5.md5(opad.tostring())
766 def digest(self, data):
767 ipad = self.ipad.copy()
768 opad = self.opad.copy()
769 ipad.update(data)
770 opad.update(ipad.digest())
771 return opad.digest()
772 #
773 # simulate server end
774 # 模拟服务器端
775 key = "this should be a well-kept secret"
776 message = open("samples/sample.txt").read()
777 signature = HMAC_MD5(key).digest(message)
778 # (send message and signature across a public network)
779 # (经过由网络发送信息和签名)
780 #
781 # simulate client end
782 #模拟客户端
783 key = "this should be a well-kept secret"
784 client_signature = HMAC_MD5(key).digest(message)
785 if client_signature == signature:
786 print "this is the original message:"
787 print
788 print message
789 else:
790 print "someone has modified the message!!!"
791 copy 方法会对这个内部对象状态做一个快照( snapshot ). 这允许你预先计算
792 部分密文摘要(例如 Example 2-38 中的 padded key).
793 该算法的细节请参阅 HMAC-MD5:Keyed-MD5 for Message Authentication
794 ( http://www.research.ibm.com/security/draft-ietf-ipsec-hmac-md5-00.t
795 xt ) by Krawczyk, 或其他.
796 千万别忘记内建的伪随机生成器对于加密操作而言并不合适. 千万小心.
797 2.20. sha 模块
798 sha 模块提供了计算信息摘要(密文)的另种方法, 如 Example 2-39 所示. 它
799 与 md5 模块类似, 但生成的是 160 位签名.
800 2.20.0.1. Example 2-39. 使用 sha 模块
801 File: sha-example-1.py
802 import sha
803 hash = sha.new()
804 hash.update("spam, spam, and eggs")
805 print repr(hash.digest())
806 print hash.hexdigest()
807 '\321\333\003\026I\331\272-j\303\247\240\345\343Tvq\364\346\311'
808 d1db031649d9ba2d6ac3a7a0e5e3547671f4e6c9
809 关于 sha 密文的使用, 请参阅 md5 中的例子.
810 2.21. crypt 模块
811 (可选, 只用于 Unix) crypt 模块实现了单向的 DES 加密, Unix 系统使用这个
812 加密算法来储存密码, 这个模块真正也就只在检查这样的密码时有用.
813 Example 2-40 展示了如何使用 crypt.crypt 来加密一个密码, 将密码和 salt
814 组合起来然后传递给函数, 这里的 salt 包含两位随机字符. 现在你可以扔掉
815 原密码而只保存加密后的字符串了.
816 2.21.0.1. Example 2-40. 使用 crypt 模块
817 File: crypt-example-1.py
818 import crypt
819 import random, string
820 def getsalt(chars = string.letters + string.digits):
821 # generate a random 2-character 'salt'
822 # 生成随机的 2 字符 'salt'
823 return random.choice(chars) + random.choice(chars)
824 print crypt.crypt("bananas", getsalt())
825 'py8UGrijma1j6'
826 确认密码时, 只需要用新密码调用加密函数, 并取加密后字符串的前两位作为
827 salt 即可. 如果结果和加密后字符串匹配, 那么密码就是正确的. Example
828 2-41 使用 pwd 模块来获取已知用户的加密后密码.
829 2.21.0.2. Example 2-41. 使用 crypt 模块身份验证
830 File: crypt-example-2.py
831 import pwd, crypt
832 def login(user, password):
833 "Check if user would be able to log in using password"
834 try:
835 pw1 = pwd.getpwnam(user)[1]
836 pw2 = crypt.crypt(password, pw1[:2])
837 return pw1 == pw2
838 except KeyError:
839 return 0 # no such user
840 user = raw_input("username:")
841 password = raw_input("password:")
842 if login(user, password):
843 print "welcome", user
844 else:
845 print "login failed"
846 关于其他实现验证的方法请参阅 md5 模块一节.
847 2.22. rotor 模块
848 这个模块在 2.3 时被声明不赞成, 2.4 时废了. 因为它的加密算法不安全.
849 - Feather
850 (可选) rotor 模块实现了一个简单的加密算法. 如 Example 2-42 所示. 它的
851 算法基于 WWII Enigma engine.
852 2.22.0.1. Example 2-42. 使用 rotor 模块
853 File: rotor-example-1.py
854 import rotor
855 SECRET_KEY = "spam"
856 MESSAGE = "the holy grail"
857 r = rotor.newrotor(SECRET_KEY)
858 encoded_message = r.encrypt(MESSAGE)
859 decoded_message = r.decrypt(encoded_message)
860 print "original:", repr(MESSAGE)
861 print "encoded message:", repr(encoded_message)
862 print "decoded message:", repr(decoded_message)
863 original: 'the holy grail'
864 encoded message: '\227\271\244\015\305sw\3340\337\252\237\340U'
865 decoded message: 'the holy grail'
866 2.23. zlib 模块
867 (可选) zlib 模块为 "zlib" 压缩提供支持. (这种压缩方法是 "deflate".)
868 Example 2-43 展示了如何使用 compress 和 decompress 函数接受字符串参
869 数.
870 2.23.0.1. Example 2-43. 使用 zlib 模块压缩字符串
871 File: zlib-example-1.py
872 import zlib
873 MESSAGE = "life of brian"
874 compressed_message = zlib.compress(MESSAGE)
875 decompressed_message = zlib.decompress(compressed_message)
876 print "original:", repr(MESSAGE)
877 print "compressed message:", repr(compressed_message)
878 print "decompressed message:", repr(decompressed_message)
879 original: 'life of brian'
880 compressed message:
881 'x\234\313\311LKU\310OSH*\312L\314\003\000!\010\004\302'
882 decompressed message: 'life of brian'
883 文件的内容决定了压缩比率, Example 2-44 说明了这点.
884 2.23.0.2. Example 2-44. 使用 zlib 模块压缩多个不同类型文件
885 File: zlib-example-2.py
886 import zlib
887 import glob
888 for file in glob.glob("samples/*"):
889 indata = open(file, "rb").read()
890 outdata = zlib.compress(indata, zlib.Z_BEST_COMPRESSION)
891 print file, len(indata), "=>", len(outdata),
892 print "%d%%" % (len(outdata) * 100 / len(indata))
893 samples\sample.au 1676 => 1109 66%
894 samples\sample.gz 42 => 51 121%
895 samples\sample.htm 186 => 135 72%
896 samples\sample.ini 246 => 190 77%
897 samples\sample.jpg 4762 => 4632 97%
898 samples\sample.msg 450 => 275 61%
899 samples\sample.sgm 430 => 321 74%
900 samples\sample.tar 10240 => 125 1%
901 samples\sample.tgz 155 => 159 102%
902 samples\sample.txt 302 => 220 72%
903 samples\sample.wav 13260 => 10992 82%
904 你也可以实时地压缩或解压缩数据, 如 Example 2-45 所示.
905 2.23.0.3. Example 2-45. 使用 zlib 模块解压缩流
906 File: zlib-example-3.py
907 import zlib
908 encoder = zlib.compressobj()
909 data = encoder.compress("life")
910 data = data + encoder.compress(" of ")
911 data = data + encoder.compress("brian")
912 data = data + encoder.flush()
913 print repr(data)
914 print repr(zlib.decompress(data))
915 'x\234\313\311LKU\310OSH*\312L\314\003\000!\010\004\302'
916 'life of brian'
917 Example 2-46 把解码对象封装到了一个类似文件对象的类中, 实现了一些文件
918 对象的方法, 这样使得读取压缩文件更方便.
919 2.23.0.4. Example 2-46. 压缩流的仿文件访问方式
920 File: zlib-example-4.py
921 import zlib
922 import string, StringIO
923 class ZipInputStream:
924 def _ _init_ _(self, file):
925 self.file = file
926 self._ _rewind()
927 def _ _rewind(self):
928 self.zip = zlib.decompressobj()
929 self.pos = 0 # position in zipped stream
930 self.offset = 0 # position in unzipped stream
931 self.data = ""
932 def _ _fill(self, bytes):
933 if self.zip:
934 # read until we have enough bytes in the buffer
935 while not bytes or len(self.data) < bytes:
936 self.file.seek(self.pos)
937 data = self.file.read(16384)
938 if not data:
939 self.data = self.data + self.zip.flush()
940 self.zip = None # no more data
941 break
942 self.pos = self.pos + len(data)
943 self.data = self.data + self.zip.decompress(data)
944 def seek(self, offset, whence=0):
945 if whence == 0:
946 position = offset
947 elif whence == 1:
948 position = self.offset + offset
949 else:
950 raise IOError, "Illegal argument"
951 if position < self.offset:
952 raise IOError, "Cannot seek backwards"
953 # skip forward, in 16k blocks
954 while position > self.offset:
955 if not self.read(min(position - self.offset, 16384)):
956 break
957 def tell(self):
958 return self.offset
959 def read(self, bytes = 0):
960 self._ _fill(bytes)
961 if bytes:
962 data = self.data[:bytes]
963 self.data = self.data[bytes:]
964 else:
965 data = self.data
966 self.data = ""
967 self.offset = self.offset + len(data)
968 return data
969 def readline(self):
970 # make sure we have an entire line
971 while self.zip and "\n" not in self.data:
972 self._ _fill(len(self.data) + 512)
973 i = string.find(self.data, "\n") + 1
974 if i <= 0:
975 return self.read()
976 return self.read(i)
977 def readlines(self):
978 lines = []
979 while 1:
980 s = self.readline()
981 if not s:
982 break
983 lines.append(s)
984 return lines
985 #
986 # try it out
987 data = open("samples/sample.txt").read()
988 data = zlib.compress(data)
989 file = ZipInputStream(StringIO.StringIO(data))
990 for line in file.readlines():
991 print line[:-1]
992 We will perhaps eventually be writing only small
993 modules which are identified by name as they are
994 used to build larger ones, so that devices like
995 indentation, rather than delimiters, might become
996 feasible for expressing local structure in the
997 source language.
998 -- Donald E. Knuth, December 1974
999 2.24. code 模块
1000 code 模块提供了一些用于模拟标准交互解释器行为的函数.
1001 compile_command 与内建 compile 函数行为相似, 但它会通过测试来保证你传
1002 递的是一个完成的 Python 语句.
1003 在 Example 2-47 中, 我们一行一行地编译一个程序, 编译完成后会执行所得
1004 到的代码对象 (code object). 程序代码如下:
1005 a = (
1006 1,
1007 2,
1008 3
1009 )
1010 print a
1011 注意只有我们到达第 2 个括号, 元组的赋值操作能编译完成.
1012 2.24.0.1. Example 2-47. 使用 code 模块编译语句
1013 File: code-example-1.py
1014 import code
1015 import string
1016 #
1017 SCRIPT = [
1018 "a = (",
1019 " 1,",
1020 " 2,",
1021 " 3 ",
1022 ")",
1023 "print a"
1024 ]
1025 script = ""
1026 for line in SCRIPT:
1027 script = script + line + "\n"
1028 co = code.compile_command(script, "<stdin>", "exec")
1029 if co:
1030 # got a complete statement. execute it!
1031 print "-"*40
1032 print script,
1033 print "-"*40
1034 exec co
1035 script = ""
1036 ----------------------------------------
1037 a = (
1038 1,
1039 2,
1040 3
1041 )
1042 ----------------------------------------
1043 ----------------------------------------
1044 print a
1045 ----------------------------------------
1046 (1, 2, 3)
1047 InteractiveConsole 类实现了一个交互控制台, 类似你启动的 Python 解释器
1048 交互模式.
1049 控制台可以是活动的(自动调用函数到达下一行) 或是被动的(当有新数据时调
1050 用 push 方法). 默认使用内建的 raw_input 函数. 如果你想使用另个输入函
1051 数, 你可以使用相同的名称重载这个方法. Example 2-48 展示了如何使用 code
1052 模块来模拟交互解释器.
1053 2.24.0.2. Example 2-48. 使用 code 模块模拟交互解释器
1054 File: code-example-2.py
1055 import code
1056 console = code.InteractiveConsole()
1057 console.interact()
1058 Python 1.5.2
1059 Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
1060 (InteractiveConsole)
1061 >>> a = (
1062 ... 1,
1063 ... 2,
1064 ... 3
1065 ... )
1066 >>> print a
1067 (1, 2, 3)
1068 Example 2-49 中的脚本定义了一个 keyboard 函数. 它允许你在程序中手动控
1069 制交互解释器.
1070 2.24.0.3. Example 2-49. 使用 code 模块实现简单的 Debugging
1071 File: code-example-3.py
1072 def keyboard(banner=None):
1073 import code, sys
1074 # use exception trick to pick up the current frame
1075 try:
1076 raise None
1077 except:
1078 frame = sys.exc_info()[2].tb_frame.f_back
1079 # evaluate commands in current namespace
1080 namespace = frame.f_globals.copy()
1081 namespace.update(frame.f_locals)
1082 code.interact(banner=banner, local=namespace)
1083 def func():
1084 print "START"
1085 a = 10
1086 keyboard()
1087 print "END"
1088 func()
1089 START
1090 Python 1.5.2
1091 Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
1092 (InteractiveConsole)
1093 >>> print a
1094 10
1095 >>> print keyboard
1096 <function keyboard at 9032c8>
1097 ^Z
1098 END
1 3. 线程和进程python标准库实例-3线程和进程
2 o 3.1. 概览
3 o 3.2. threading 模块
4 o 3.3. Queue 模块
5 o 3.4. thread 模块
6 o 3.5. commands 模块
7 o 3.6. pipes 模块
8 o 3.7. popen2 模块
9 o 3.8. signal 模块
10
11 3. 线程和进程
12 "Well, since you last asked us to stop, this thread has moved from
13 discussing languages suitable for professional programmers via
14 accidental users to computer-phobic users. A few more iterations can make
15 this thread really interesting..."
16 - eff-bot, June 1996
17 3.1. 概览
18 本章将介绍标准 Python 解释器中所提供的线程支持模块. 注意线程支持模块
19 是可选的, 有可能在一些 Python 解释器中不可用.
20 本章还涵盖了一些 Unix 和 Windows 下用于执行外部进程的模块.
21 3.1.1. 线程
22 执行 Python 程序的时候, 是按照从主模块顶端向下执行的. 循环用于重复执
23 行部分代码, 函数和方法会将控制临时移交到程序的另一部分.
24 通过线程, 你的程序可以在同时处理多个任务. 每个线程都有它自己的控制流.
25 所以你可以在一个线程里从文件读取数据, 另个向屏幕输出内容.
26 为了保证两个线程可以同时访问相同的内部数据, Python 使用了 global
27 interpreter lock (全局解释器锁) . 在同一时间只可能有一个线程执行
28 Python 代码; Python 实际上是自动地在一段很短的时间后切换到下个线程执
29 行, 或者等待 一个线程执行一项需要时间的操作(例如等待通过 socket 传输
30 的数据, 或是从文件中读取数据).
31 全局锁事实上并不能避免你程序中的问题. 多个线程尝试访问相同的数据会导
32 致异常 状态. 例如以下的代码:
33 def getitem(key):
34 item = cache.get(key)
35 if item is None:
36 # not in cache; create a new one
37 item = create_new_item(key)
38 cache[key] = item
39 return item
40 如果不同的线程先后使用相同的 key 调用这里的 getitem 方法, 那么它们很
41 可能会导致相同的参数调用两次 create_new_item . 大多时候这样做没有问题,
42 但在某些时候会导致严重错误.
43 不过你可以使用 lock objects 来同步线程. 一个线程只能拥有一个 lock
44 object , 这样就可以确保某个时刻 只有一个线程执行 getitem 函数.
45 3.1.2. 进程
46 在大多现代操作系统中, 每个程序在它自身的进程( process ) 内执行. 我们通
47 过在 shell 中键入命令或直接在菜单中选择来执行一个程序/进程. Python 允
48 许你在一个脚本内执行一个新的程序.
49 大多进程相关函数通过 os 模块定义. 相关内容请参阅 第 1.4.4 小节 .
50 3.2. threading 模块
51 (可选) threading 模块为线程提供了一个高级接口, 如 Example 3-1 所示. 它
52 源自 Java 的线程实现. 和低级的 thread 模块相同, 只有你在编译解释器时
53 打开了线程支持才可以使用它 .
54 你只需要继承 Thread 类, 定义好 run 方法, 就可以创建一 个新的线程. 使
55 用时首先创建该类的一个或多个实例, 然后调用 start 方法. 这样每个实例的
56 run 方法都会运行在它自己的线程里.
57 3.2.0.1. Example 3-1. 使用 threading 模块
58 File: threading-example-1.py
59 import threading
60 import time, random
61 class Counter:
62 def _ _init_ _(self):
63 self.lock = threading.Lock()
64 self.value = 0
65 def increment(self):
66 self.lock.acquire() # critical section
67 self.value = value = self.value + 1
68 self.lock.release()
69 return value
70 counter = Counter()
71 class Worker(threading.Thread):
72 def run(self):
73 for i in range(10):
74 # pretend we're doing something that takes 10?00 ms
75 value = counter.increment() # increment global counter
76 time.sleep(random.randint(10, 100) / 1000.0)
77 print self.getName(), "-- task", i, "finished", value
78 #
79 # try it
80 for i in range(10):
81 Worker().start() # start a worker
82 Thread-1 -- task 0 finished 1
83 Thread-3 -- task 0 finished 3
84 Thread-7 -- task 0 finished 8
85 Thread-1 -- task 1 finished 7
86 Thread-4 -- task 0 Thread-5 -- task 0 finished 4
87 finished 5
88 Thread-8 -- task 0 Thread-6 -- task 0 finished 9
89 finished 6
90 ...
91 Thread-6 -- task 9 finished 98
92 Thread-4 -- task 9 finished 99
93 Thread-9 -- task 9 finished 100
94 Example 3-1 使用了 Lock 对象来在全局 Counter 对象里创建临界区
95 (critical section). 如果删除了 acquire 和 release 语句, 那么 Counter
96 很可能不会到达 100.
97 3.3. Queue 模块
98 Queue 模块提供了一个线程安全的队列 (queue) 实现, 如 Example 3-2 所示.
99 你可以通过它在多个线程里安全访问同个对象.
100 3.3.0.1. Example 3-2. 使用 Queue 模块
101 File: queue-example-1.py
102 import threading
103 import Queue
104 import time, random
105 WORKERS = 2
106 class Worker(threading.Thread):
107 def _ _init_ _(self, queue):
108 self._ _queue = queue
109 threading.Thread._ _init_ _(self)
110 def run(self):
111 while 1:
112 item = self._ _queue.get()
113 if item is None:
114 break # reached end of queue
115 # pretend we're doing something that takes 10?00 ms
116 time.sleep(random.randint(10, 100) / 1000.0)
117 print "task", item, "finished"
118 #
119 # try it
120 queue = Queue.Queue(0)
121 for i in range(WORKERS):
122 Worker(queue).start() # start a worker
123 for i in range(10):
124 queue.put(i)
125 for i in range(WORKERS):
126 queue.put(None) # add end-of-queue markers
127 task 1 finished
128 task 0 finished
129 task 3 finished
130 task 2 finished
131 task 4 finished
132 task 5 finished
133 task 7 finished
134 task 6 finished
135 task 9 finished
136 task 8 finished
137 Example 3-3 展示了如何限制队列的大小. 如果队列满了, 那么控制主线程
138 (producer threads) 被阻塞, 等待项目被弹出 (pop off).
139 3.3.0.2. Example 3-3. 使用限制大小的 Queue 模块
140 File: queue-example-2.py
141 import threading
142 import Queue
143 import time, random
144 WORKERS = 2
145 class Worker(threading.Thread):
146 def _ _init_ _(self, queue):
147 self._ _queue = queue
148 threading.Thread._ _init_ _(self)
149 def run(self):
150 while 1:
151 item = self._ _queue.get()
152 if item is None:
153 break # reached end of queue
154 # pretend we're doing something that takes 10?00 ms
155 time.sleep(random.randint(10, 100) / 1000.0)
156 print "task", item, "finished"
157 #
158 # run with limited queue
159 queue = Queue.Queue(3)
160 for i in range(WORKERS):
161 Worker(queue).start() # start a worker
162 for item in range(10):
163 print "push", item
164 queue.put(item)
165 for i in range(WORKERS):
166 queue.put(None) # add end-of-queue markers
167 push 0
168 push 1
169 push 2
170 push 3
171 push 4
172 push 5
173 task 0 finished
174 push 6
175 task 1 finished
176 push 7
177 task 2 finished
178 push 8
179 task 3 finished
180 push 9
181 task 4 finished
182 task 6 finished
183 task 5 finished
184 task 7 finished
185 task 9 finished
186 task 8 finished
187 你可以通过继承 Queue 类来修改它的行为. Example 3-4 为我们展示了一个简
188 单的具有优先级的队列. 它接受一个元组作为参数, 元组的第一个成员表示优
189 先级(数值越小优先级越高).
190 3.3.0.3. Example 3-4. 使用 Queue 模块实现优先级队列
191 File: queue-example-3.py
192 import Queue
193 import bisect
194 Empty = Queue.Empty
195 class PriorityQueue(Queue.Queue):
196 "Thread-safe priority queue"
197 def _put(self, item):
198 # insert in order
199 bisect.insort(self.queue, item)
200 #
201 # try it
202 queue = PriorityQueue(0)
203 # add items out of order
204 queue.put((20, "second"))
205 queue.put((10, "first"))
206 queue.put((30, "third"))
207 # print queue contents
208 try:
209 while 1:
210 print queue.get_nowait()
211 except Empty:
212 pass
213 third
214 second
215 first
216 Example 3-5 展示了一个简单的堆栈 (stack) 实现 (末尾添加, 头部弹出, 而
217 非头部添加, 头部弹出).
218 3.3.0.4. Example 3-5. 使用 Queue 模块实现一个堆栈
219 File: queue-example-4.py
220 import Queue
221 Empty = Queue.Empty
222 class Stack(Queue.Queue):
223 "Thread-safe stack"
224 def _put(self, item):
225 # insert at the beginning of queue, not at the end
226 self.queue.insert(0, item)
227 # method aliases
228 push = Queue.Queue.put
229 pop = Queue.Queue.get
230 pop_nowait = Queue.Queue.get_nowait
231 #
232 # try it
233 stack = Stack(0)
234 # push items on stack
235 stack.push("first")
236 stack.push("second")
237 stack.push("third")
238 # print stack contents
239 try:
240 while 1:
241 print stack.pop_nowait()
242 except Empty:
243 pass
244 third
245 second
246 first
247 3.4. thread 模块
248 (可选) thread 模块提为线程提供了一个低级 (low_level) 的接口, 如
249 Example 3-6 所示. 只有你在编译解释器时打开了线程支持才可以使用它. 如
250 果没有特殊需要, 最好使用高级接口 threading 模块替代.
251 3.4.0.1. Example 3-6. 使用 thread 模块
252 File: thread-example-1.py
253 import thread
254 import time, random
255 def worker():
256 for i in range(50):
257 # pretend we're doing something that takes 10?00 ms
258 time.sleep(random.randint(10, 100) / 1000.0)
259 print thread.get_ident(), "-- task", i, "finished"
260 #
261 # try it out!
262 for i in range(2):
263 thread.start_new_thread(worker, ())
264 time.sleep(1)
265 print "goodbye!"
266 311 -- task 0 finished
267 265 -- task 0 finished
268 265 -- task 1 finished
269 311 -- task 1 finished
270 ...
271 265 -- task 17 finished
272 311 -- task 13 finished
273 265 -- task 18 finished
274 goodbye!
275 注意当主程序退出的时候, 所有的线程也随着退出. 而 threading 模块不存在
276 这个问题 . (该行为可改变)
277 3.5. commands 模块
278 (只用于 Unix) commands 模块包含一些用于执行外部命令的函数. Example 3-7
279 展示了这个模块.
280 3.5.0.1. Example 3-7. 使用 commands 模块
281 File: commands-example-1.py
282 import commands
283 stat, output = commands.getstatusoutput("ls -lR")
284 print "status", "=>", stat
285 print "output", "=>", len(output), "bytes"
286 status => 0
287 output => 171046 bytes
288 3.6. pipes 模块
289 (只用于 Unix) pipes 模块提供了 "转换管道 (conversion pipelines)" 的支
290 持. 你可以创建包含许多外部工具调用的管道来处理多个文件. 如 Example
291 3-8 所示.
292 3.6.0.1. Example 3-8. 使用 pipes 模块
293 File: pipes-example-1.py
294 import pipes
295 t = pipes.Template()
296 # create a pipeline
297 # 这里 " - " 代表从标准输入读入内容
298 t.append("sort", "--")
299 t.append("uniq", "--")
300 # filter some text
301 # 这里空字符串代表标准输出
302 t.copy("samples/sample.txt", "")
303 Alan Jones (sensible party)
304 Kevin Phillips-Bong (slightly silly)
305 Tarquin
306 Fin-tim-lin-bin-whin-bim-lin-bus-stop-F'tang-F'tang-Olé-Biscuitbarre
307 l
308 3.7. popen2 模块
309 popen2 模块允许你执行外部命令, 并通过流来分别访问它的 stdin 和 stdout
310 ( 可能还有 stderr ).
311 在 python 1.5.2 以及之前版本, 该模块只存在于 Unix 平台上. 2.0 后,
312 Windows 下也实现了该函数. Example 3-9 展示了如何使用该模块来给字符串排
313 序.
314 3.7.0.1. Example 3-9. 使用 popen2 模块对字符串排序Module to Sort
315 Strings
316 File: popen2-example-1.py
317 import popen2, string
318 fin, fout = popen2.popen2("sort")
319 fout.write("foo\n")
320 fout.write("bar\n")
321 fout.close()
322 print fin.readline(),
323 print fin.readline(),
324 fin.close()
325 bar
326 foo
327 Example 3-10 展示了如何使用该模块控制应用程序 .
328 3.7.0.2. Example 3-10. 使用 popen2 模块控制 gnuchess
329 File: popen2-example-2.py
330 import popen2
331 import string
332 class Chess:
333 "Interface class for chesstool-compatible programs"
334 def _ _init_ _(self, engine = "gnuchessc"):
335 self.fin, self.fout = popen2.popen2(engine)
336 s = self.fin.readline()
337 if s != "Chess\n":
338 raise IOError, "incompatible chess program"
339 def move(self, move):
340 self.fout.write(move + "\n")
341 self.fout.flush()
342 my = self.fin.readline()
343 if my == "Illegal move":
344 raise ValueError, "illegal move"
345 his = self.fin.readline()
346 return string.split(his)[2]
347 def quit(self):
348 self.fout.write("quit\n")
349 self.fout.flush()
350 #
351 # play a few moves
352 g = Chess()
353 print g.move("a2a4")
354 print g.move("b2b3")
355 g.quit()
356 b8c6
357 e7e5
358 3.8. signal 模块
359 你可以使用 signal 模块配置你自己的信号处理器 (signal handler), 如
360 Example 3-11 所示. 当解释器收到某个信号时, 信号处理器会立即执行.
361 3.8.0.1. Example 3-11. 使用 signal 模块
362 File: signal-example-1.py
363 import signal
364 import time
365 def handler(signo, frame):
366 print "got signal", signo
367 signal.signal(signal.SIGALRM, handler)
368 # wake me up in two seconds
369 signal.alarm(2)
370 now = time.time()
371 time.sleep(200)
372 print "slept for", time.time() - now, "seconds"
373 got signal 14
374 slept for 1.99262607098 seconds
375 4. 数据表示
376 "PALO ALTO, Calif. - Intel says its Pentium Pro and new Pentium II chips
377 have a flaw that can cause computers to sometimes make mistakes but said
378 the problems could be fixed easily with rewritten software."
379 - Reuters telegram
1 4. 数据表示python标准库实例-4数据表示
2 o 4.1. 概览
3 o 4.2. array 模块
4 o 4.3. struct 模块
5 o 4.4. xdrlib 模块
6 o 4.5. marshal 模块
7 o 4.6. pickle 模块
8 o 4.7. cPickle 模块
9 o 4.8. copy_reg 模块
10 o 4.9. pprint 模块
11 o 4.10. repr 模块
12 o 4.11. base64 模块
13 o 4.12. binhex 模块
14 o 4.13. quopri 模块
15 o 4.14. uu 模块
16 o 4.15. binascii 模块
17
18
19 4.1. 概览
20 本章描述了一些用于在 Python 对象和其他数据表示类型间相互转换的模块.
21 这些模块通常用于读写特定的文件格式或是储存/取出 Python 变量.
22 4.1.1. 二进制数据
23 Python 提供了一些用于二进制数据解码/编码的模块. struct 模块用于在二进
24 制数据结构(例如 C 中的 struct )和 Python 元组间转换. array 模块将二进
25 制数据阵列 ( C arrays )封装为 Python 序列对象.
26 4.1.2. 自描述格式
27 marshal 和 pickle 模块用于在不同的 Python 程序间共享/传递数据.
28 marshal 模块使用了简单的自描述格式( Self-Describing Formats ), 它支持
29 大多的内建数据类型, 包括 code 对象. Python 自身也使用了这个格式来储存
30 编译后代码( .pyc 文件).
31 pickle 模块提供了更复杂的格式, 它支持用户定义的类, 自引用数据结构等等.
32 pickle 是用 Python 写的, 相对来说速度较慢, 不过还有一个 cPickle 模块,
33 使用 C 实现了相同的功能, 速度和 marshal 不相上下.
34 4.1.3. 输出格式
35 一些模块提供了增强的格式化输出, 用来补充内建的 repr 函数和 % 字符串格
36 式化操作符.
37 pprint 模块几乎可以将任何 Python 数据结构很好地打印出来(提高可读性).
38 repr 模块可以用来替换内建同名函数. 该模块与内建函数不同的是它限制了很
39 多输出形式: 他只会输出字符串的前 30 个字符, 它只打印嵌套数据结构的几
40 个等级, 等等.
41 4.1.4. 编码二进制数据
42 Python 支持大部分常见二进制编码, 例如 base64 , binhex (一种 Macintosh
43 格式) , quoted printable , 以及 uu 编码.
44 4.2. array 模块
45 array 模块实现了一个有效的阵列储存类型. 阵列和列表类似, 但其中所有的
46 项目必须为相同的类型. 该类型在阵列创建时指定.
47 Examples 4-1 到 4-5 都是很简单的范例. Example 4-1 创建了一个 array 对
48 象, 然后使用 tostring 方法将内部缓冲区( internal buffer )复制到字符串.
49 4.2.0.1. Example 4-1. 使用 array 模块将数列转换为字符串
50 File: array-example-1.py
51 import array
52 a = array.array("B", range(16)) # unsigned char
53 b = array.array("h", range(16)) # signed short
54 print a
55 print repr(a.tostring())
56 print b
57 print repr(b.tostring())
58 array('B', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
59 '\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017'
60 array('h', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
61 '\000\000\001\000\002\000\003\000\004\000\005\000\006\000\007\000
62 \010\000\011\000\012\000\013\000\014\000\015\000\016\000\017\000'
63 array 对象可以作为一个普通列表对待, 如 Example 4-2 所示. 不过, 你不能
64 连接两个不同类型的阵列.
65 4.2.0.2. Example 4-2. 作为普通序列操作阵列
66 File: array-example-2.py
67 import array
68 a = array.array("B", [1, 2, 3])
69 a.append(4)
70 a = a + a
71 a = a[2:-2]
72 print a
73 print repr(a.tostring())
74 for i in a:
75 print i,
76 array('B', [3, 4, 1, 2])
77 '\003\004\001\002'
78 3 4 1 2
79 该模块还提供了用于转换原始二进制数据到整数序列(或浮点数数列, 具体情况
80 决定)的方法, 如 Example 4-3 所示.
81 4.2.0.3. Example 4-3. 使用阵列将字符串转换为整数列表
82 File: array-example-3.py
83 import array
84 a = array.array("i", "fish license") # signed integer
85 print a
86 print repr(a.tostring())
87 print a.tolist()
88 array('i', [1752394086, 1667853344, 1702063717])
89 'fish license'
90 [1752394086, 1667853344, 1702063717]
91 最后, Example 4-4 展示了如何使用该模块判断当前平台的字节序
92 ( endianess ) .
93 4.2.0.4. Example 4-4. 使用 array 模块判断平台字节序
94 File: array-example-4.py
95 import array
96 def little_endian():
97 return ord(array.array("i",[1]).tostring()[0])
98 if little_endian():
99 print "little-endian platform (intel, alpha)"
100 else:
101 print "big-endian platform (motorola, sparc)"
102 big-endian platform (motorola, sparc)
103 Python 2.0 以及以后版本提供了 sys.byteorder 属性, 可以更简单地判断字
104 节序 (属性值为 "little " 或 "big " ), 如 Example 4-5 所示.
105 4.2.0.5. Example 4-5. 使用 sys.byteorder 属性判断平台字节序( Python
106 2.0 及以后)
107 File: sys-byteorder-example-1.py
108 import sys
109 # 2.0 and later
110 if sys.byteorder == "little":
111 print "little-endian platform (intel, alpha)"
112 else:
113 print "big-endian platform (motorola, sparc)"
114 big-endian platform (motorola, sparc)
115 4.3. struct 模块
116 struct 模块用于转换二进制字符串和 Python 元组. pack 函数接受格式字符
117 串以及额外参数, 根据指定格式将额外参数转换为二进制字符串. upack 函数
118 接受一个字符串作为参数, 返回一个元组. 如 Example 4-6 所示.
119 4.3.0.1. Example 4-6. 使用 struct 模块
120 File: struct-example-1.py
121 import struct
122 # native byteorder
123 buffer = struct.pack("ihb", 1, 2, 3)
124 print repr(buffer)
125 print struct.unpack("ihb", buffer)
126 # data from a sequence, network byteorder
127 data = [1, 2, 3]
128 buffer = apply(struct.pack, ("!ihb",) + tuple(data))
129 print repr(buffer)
130 print struct.unpack("!ihb", buffer)
131 # in 2.0, the apply statement can also be written as:
132 # buffer = struct.pack("!ihb", *data)
133 '\001\000\000\000\002\000\003'
134 (1, 2, 3)
135 '\000\000\000\001\000\002\003'
136 (1, 2, 3)
137 4.4. xdrlib 模块
138 xdrlib 模块用于在 Python 数据类型和 Sun 的 external data
139 representation (XDR) 间相互转化, 如 Example 4-7 所示.
140 4.4.0.1. Example 4-7. 使用 xdrlib 模块
141 File: xdrlib-example-1.py
142 import xdrlib
143 #
144 # create a packer and add some data to it
145 p = xdrlib.Packer()
146 p.pack_uint(1)
147 p.pack_string("spam")
148 data = p.get_buffer()
149 print "packed:", repr(data)
150 #
151 # create an unpacker and use it to decode the data
152 u = xdrlib.Unpacker(data)
153 print "unpacked:", u.unpack_uint(), repr(u.unpack_string())
154 u.done()
155 packed: '\000\000\000\001\000\000\000\004spam'
156 unpacked: 1 'spam'
157 Sun 在 remote procedure call (RPC) 协议中使用了 XDR 格式. Example 4-8
158 虽然不完整, 但它展示了如何建立一个 RPC 请求包.
159 4.4.0.2. Example 4-8. 使用 xdrlib 模块发送 RPC 调用包
160 File: xdrlib-example-2.py
161 import xdrlib
162 # some constants (see the RPC specs for details)
163 RPC_CALL = 1
164 RPC_VERSION = 2
165 MY_PROGRAM_ID = 1234 # assigned by Sun
166 MY_VERSION_ID = 1000
167 MY_TIME_PROCEDURE_ID = 9999
168 AUTH_NULL = 0
169 transaction = 1
170 p = xdrlib.Packer()
171 # send a Sun RPC call package
172 p.pack_uint(transaction)
173 p.pack_enum(RPC_CALL)
174 p.pack_uint(RPC_VERSION)
175 p.pack_uint(MY_PROGRAM_ID)
176 p.pack_uint(MY_VERSION_ID)
177 p.pack_uint(MY_TIME_PROCEDURE_ID)
178 p.pack_enum(AUTH_NULL)
179 p.pack_uint(0)
180 p.pack_enum(AUTH_NULL)
181 p.pack_uint(0)
182 print repr(p.get_buffer())
183 '\000\000\000\001\000\000\000\001\000\000\000\002\000\000\004\322
184 \000\000\003\350\000\000\'\017\000\000\000\000\000\000\000\000\000
185 \000\000\000\000\000\000\000'
186 4.5. marshal 模块
187 marshal 模块可以把不连续的数据组合起来 - 与字符串相互转化, 这样它们就
188 可以写入文件或是在网络中传输. 如 Example 4-9 所示.
189 marshal 模块使用了简单的自描述格式. 对于每个数据项目, 格式化后的字符
190 串都包含一个类型代码, 然后是一个或多个类型标识区域. 整数使用小字节序
191 ( little-endian order )储存, 字符串储存时和它自身内容长度相同(可能包含
192 空字节), 元组由组成它的对象组合表示.
193 4.5.0.1. Example 4-9. 使用 marshal 模块组合不连续数据
194 File: marshal-example-1.py
195 import marshal
196 value = (
197 "this is a string",
198 [1, 2, 3, 4],
199 ("more tuples", 1.0, 2.3, 4.5),
200 "this is yet another string"
201 )
202 data = marshal.dumps(value)
203 # intermediate format
204 print type(data), len(data)
205 print "-"*50
206 print repr(data)
207 print "-"*50
208 print marshal.loads(data)
209 <type 'string'> 118
210 --------------------------------------------------
211 '(\004\000\000\000s\020\000\000\000this is a string
212 [\004\000\000\000i\001\000\000\000i\002\000\000\000
213 i\003\000\000\000i\004\000\000\000(\004\000\000\000
214 s\013\000\000\000more tuplesf\0031.0f\0032.3f\0034.
215 5s\032\000\000\000this is yet another string'
216 --------------------------------------------------
217 ('this is a string', [1, 2, 3, 4], ('more tuples',
218 1.0, 2.3, 4.5), 'this is yet another string')
219 marshal 模块还可以处理 code 对象(它用于储存预编译的 Python 模块). 如
220 Example 4-10 所示.
221 4.5.0.2. Example 4-10. 使用 marshal 模块处理代码
222 File: marshal-example-2.py
223 import marshal
224 script = """
225 print 'hello'
226 """
227 code = compile(script, "<script>", "exec")
228 data = marshal.dumps(code)
229 # intermediate format
230 print type(data), len(data)
231 print "-"*50
232 print repr(data)
233 print "-"*50
234 exec marshal.loads(data)
235 <type 'string'> 81
236 --------------------------------------------------
237 'c\000\000\000\000\001\000\000\000s\017\000\000\00
238 0\177\000\000\177\002\000d\000\000GHd\001\000S(\00
239 2\000\000\000s\005\000\000\000helloN(\000\000\000\
240 000(\000\000\000\000s\010\000\000\000<script>s\001
241 \000\000\000?\002\000s\000\000\000\000'
242 --------------------------------------------------
243 hello
244 4.6. pickle 模块
245 pickle 模块同 marshal 模块相同, 将数据连续化, 便于保存传输. 它比
246 marshal 要慢一些, 但它可以处理类实例, 共享的元素, 以及递归数据结构等.
247 4.6.0.1. Example 4-11. 使用 pickle 模块
248 File: pickle-example-1.py
249 import pickle
250 value = (
251 "this is a string",
252 [1, 2, 3, 4],
253 ("more tuples", 1.0, 2.3, 4.5),
254 "this is yet another string"
255 )
256 data = pickle.dumps(value)
257 # intermediate format
258 print type(data), len(data)
259 print "-"*50
260 print data
261 print "-"*50
262 print pickle.loads(data)
263 <type 'string'> 121
264 --------------------------------------------------
265 (S'this is a string'
266 p0
267 (lp1
268 I1
269 aI2
270 aI3
271 aI4
272 a(S'more tuples'
273 p2
274 F1.0
275 F2.3
276 F4.5
277 tp3
278 S'this is yet another string'
279 p4
280 tp5
281 .
282 --------------------------------------------------
283 ('this is a string', [1, 2, 3, 4], ('more tuples',
284 1.0, 2.3, 4.5), 'this is yet another string')
285 不过另一方面, pickle 不能处理 code 对象(可以参阅 copy_reg 模块来完成
286 这个).
287 默认情况下, pickle 使用急于文本的格式. 你也可以使用二进制格式, 这样数
288 字和二进制字符串就会以紧密的格式储存, 这样文件就会更小点. 如 Example
289 4-12 所示.
290 4.6.0.2. Example 4-12. 使用 pickle 模块的二进制模式
291 File: pickle-example-2.py
292 import pickle
293 import math
294 value = (
295 "this is a long string" * 100,
296 [1.2345678, 2.3456789, 3.4567890] * 100
297 )
298 # text mode
299 data = pickle.dumps(value)
300 print type(data), len(data), pickle.loads(data) == value
301 # binary mode
302 data = pickle.dumps(value, 1)
303 print type(data), len(data), pickle.loads(data) == value
304 4.7. cPickle 模块
305 (可选, 注意大小写) cPickle 模块是针对 pickle 模块的一个更快的实现. 如
306 Example 4-13 所示.
307 4.7.0.1. Example 4-13. 使用 cPickle 模块
308 File: cpickle-example-1.py
309 try:
310 import cPickle
311 pickle = cPickle
312 except ImportError:
313 import pickle
314 4.8. copy_reg 模块
315 你可以使用 copy_reg 模块注册你自己的扩展类型. 这样 pickle 和 copy 模
316 块就会知道如何处理非标准类型.
317 例如, 标准的 pickle 实现不能用来处理 Python code 对象, 如下所示:
318 File: copy-reg-example-1.py
319 import pickle
320 CODE = """
321 print 'good evening'
322 """
323 code = compile(CODE, "<string>", "exec")
324 exec code
325 exec pickle.loads(pickle.dumps(code))
326 good evening
327 Traceback (innermost last):
328 ...
329 pickle.PicklingError: can't pickle 'code' objects
330 我们可以注册一个 code 对象处理器来完成目标. 处理器应包含两个部分: 一
331 个 pickler , 接受 code 对象并返回一个只包含简单数据类型的元组, 以及一
332 个 unpickler , 作用相反, 接受这样的元组作为参数. 如 Example 4-14 所示.
333 4.8.0.1. Example 4-14. 使用 copy_reg 模块实现 code 对象的 pickle 操作
334 File: copy-reg-example-2.py
335 import copy_reg
336 import pickle, marshal, types
337 #
338 # register a pickle handler for code objects
339 def code_unpickler(data):
340 return marshal.loads(data)
341 def code_pickler(code):
342 return code_unpickler, (marshal.dumps(code),)
343 copy_reg.pickle(types.CodeType, code_pickler, code_unpickler)
344 #
345 # try it out
346 CODE = """
347 print "suppose he's got a pointed stick"
348 """
349 code = compile(CODE, "<string>", "exec")
350 exec code
351 exec pickle.loads(pickle.dumps(code))
352 suppose he's got a pointed stick
353 suppose he's got a pointed stick
354 如果你是在网络中传输 pickle 后的数据, 那么请确保自定义的 unpickler 在
355 数据接收端也是可用的.
356 Example 4-15 展示了如何实现 pickle 一个打开的文件对象.
357 4.8.0.2. Example 4-15. 使用 copy_reg 模块实现文件对象的 pickle 操作
358 File: copy-reg-example-3.py
359 import copy_reg
360 import pickle, types
361 import StringIO
362 #
363 # register a pickle handler for file objects
364 def file_unpickler(position, data):
365 file = StringIO.StringIO(data)
366 file.seek(position)
367 return file
368 def file_pickler(code):
369 position = file.tell()
370 file.seek(0)
371 data = file.read()
372 file.seek(position)
373 return file_unpickler, (position, data)
374 copy_reg.pickle(types.FileType, file_pickler, file_unpickler)
375 #
376 # try it out
377 file = open("samples/sample.txt", "rb")
378 print file.read(120),
379 print "<here>",
380 print pickle.loads(pickle.dumps(file)).read()
381 We will perhaps eventually be writing only small
382 modules, which are identified by name as they are
383 used to build larger <here> ones, so that devices like
384 indentation, rather than delimiters, might become
385 feasible for expressing local structure in the
386 source language.
387 -- Donald E. Knuth, December 1974
388 4.9. pprint 模块
389 pprint 模块( pretty printer )用于打印 Python 数据结构. 当你在命令行下
390 打印特定数据结构时你会发现它很有用(输出格式比较整齐, 便于阅读).
391 4.9.0.1. Example 4-16. 使用 pprint 模块
392 File: pprint-example-1.py
393 import pprint
394 data = (
395 "this is a string", [1, 2, 3, 4], ("more tuples",
396 1.0, 2.3, 4.5), "this is yet another string"
397 )
398 pprint.pprint(data)
399 ('this is a string',
400 [1, 2, 3, 4],
401 ('more tuples', 1.0, 2.3, 4.5),
402 'this is yet another string')
403 4.10. repr 模块
404 repr 模块提供了内建 repr 函数的另个版本. 它限制了很多(字符串长度, 递
405 归等). Example 4-17 展示了如何使用该模块.
406 4.10.0.1. Example 4-17. 使用 repr 模块
407 File: repr-example-1.py
408 # note: this overrides the built-in 'repr' function
409 from repr import repr
410 # an annoyingly recursive data structure
411 data = (
412 "X" * 100000,
413 )
414 data = [data]
415 data.append(data)
416 print repr(data)
417 [('XXXXXXXXXXXX...XXXXXXXXXXXXX',), [('XXXXXXXXXXXX...XXXXXXXXXX
418 XXX',), [('XXXXXXXXXXXX...XXXXXXXXXXXXX',), [('XXXXXXXXXXXX...XX
419 XXXXXXXXXXX',), [('XXXXXXXXXXXX...XXXXXXXXXXXXX',), [(...), [...
420 ]]]]]]]
421 4.11. base64 模块
422 base64 编码体系用于将任意二进制数据转换为纯文本. 它将一个 3 字节的二
423 进制字节组转换为 4 个文本字符组储存, 而且规定只允许以下集合中的字符出
424 现:
425 ABCDEFGHIJKLMNOPQRSTUVWXYZ
426 abcdefghijklmnopqrstuvwxyz
427 0123456789+/
428 另外, = 用于填充数据流的末尾.
429 Example 4-18 展示了如何使用 encode 和 decode 函数操作文件对象.
430 4.11.0.1. Example 4-18. 使用 base64 模块编码文件
431 File: base64-example-1.py
432 import base64
433 MESSAGE = "life of brian"
434 file = open("out.txt", "w")
435 file.write(MESSAGE)
436 file.close()
437 base64.encode(open("out.txt"), open("out.b64", "w"))
438 base64.decode(open("out.b64"), open("out.txt", "w"))
439 print "original:", repr(MESSAGE)
440 print "encoded message:", repr(open("out.b64").read())
441 print "decoded message:", repr(open("out.txt").read())
442 original: 'life of brian'
443 encoded message: 'bGlmZSBvZiBicmlhbg==\012'
444 decoded message: 'life of brian'
445 Example 4-19 展示了如何使用 encodestring 和 decodestring 函数在字符串
446 间转换. 它们是 encode 和 decode 函数的顶层封装. 使用 StringIO 对象处
447 理输入和输出.
448 4.11.0.2. Example 4-19. 使用 base64 模块编码字符串
449 File: base64-example-2.py
450 import base64
451 MESSAGE = "life of brian"
452 data = base64.encodestring(MESSAGE)
453 original_data = base64.decodestring(data)
454 print "original:", repr(MESSAGE)
455 print "encoded data:", repr(data)
456 print "decoded data:", repr(original_data)
457 original: 'life of brian'
458 encoded data: 'bGlmZSBvZiBicmlhbg==\012'
459 decoded data: 'life of brian'
460 Example 4-20 展示了如何将用户名和密码转换为 HTTP 基本身份验证字符串.
461 4.11.0.3. Example 4-20. 使用 base64 模块做基本验证
462 File: base64-example-3.py
463 import base64
464 def getbasic(user, password):
465 # basic authentication (according to HTTP)
466 return base64.encodestring(user + ":" + password)
467 print getbasic("Aladdin", "open sesame")
468 'QWxhZGRpbjpvcGVuIHNlc2FtZQ=='
469 最后, Example 4-21 展示了一个实用小工具, 它可以把 GIF 格式转换为
470 Python 脚本, 便于使用 Tkinter 库.
471 4.11.0.4. Example 4-21. 使用 base64 为 Tkinter 封装 GIF 格式
472 File: base64-example-4.py
473 import base64, sys
474 if not sys.argv[1:]:
475 print "Usage: gif2tk.py giffile >pyfile"
476 sys.exit(1)
477 data = open(sys.argv[1], "rb").read()
478 if data[:4] != "GIF8":
479 print sys.argv[1], "is not a GIF file"
480 sys.exit(1)
481 print '# generated from', sys.argv[1], 'by gif2tk.py'
482 print
483 print 'from Tkinter import PhotoImage'
484 print
485 print 'image = PhotoImage(data="""'
486 print base64.encodestring(data),
487 print '""")'
488 # generated from samples/sample.gif by gif2tk.py
489 from Tkinter import PhotoImage
490 image = PhotoImage(data="""
491 R0lGODlhoAB4APcAAAAAAIAAAACAAICAAAAAgIAAgACAgICAgAQEBIwEBIyMBJRUlISE
492 /LRUBAQE
493 ...
494 AjmQBFmQBnmQCJmQCrmQDNmQDvmQEBmREnkRAQEAOw==
495 """)
496 4.12. binhex 模块
497 binhex 模块用于到 Macintosh BinHex 格式的相互转化. 如 Example 4-22 所
498 示.
499 4.12.0.1. Example 4-22. 使用 binhex 模块
500 File: binhex-example-1.py
501 import binhex
502 import sys
503 infile = "samples/sample.jpg"
504 binhex.binhex(infile, sys.stdout)
505 (This file must be converted with BinHex 4.0)
506 :#R0KEA"XC5jUF'F!2j!)!*!%%TS!N!4RdrrBrq!!%%T'58B!!3%!!!%!!3!!rpX
507 !3`!)"JB("J8)"`F(#3N)#J`8$3`,#``C%K-2&"dD(aiG'K`F)#3Z*b!L,#-F(#J
508 h+5``-63d0"mR16di-M`Z-c3brpX!3`%*#3N-#``B$3dB-L%F)6+3-[r!!"%)!)!
509 !J!-")J!#%3%$%3(ra!!I!!!""3'3"J#3#!%#!`3&"JF)#3S,rm3!Y4!!!J%$!`)
510 %!`8&"!3!!!&p!3)$!!34"4)K-8%'%e&K"b*a&$+"ND%))d+a`495dI!N-f*bJJN
511 该模块有两个函数 binhex 和 hexbin .
512 4.13. quopri 模块
513 quopri 模块基于 MIME 标准实现了引用的可打印编码( quoted printable
514 encoding ).
515 这样的编码可以将不包含或只包含一部分U.S. ASCII 文本的信息, 例如大多欧
516 洲语言, 中文, 转换为只包含 U.S. ASCII 的信息. 在一些老式的 mail 代理
517 中你会发现这很有用, 因为它们一般不支持特殊. 如 Example 4-23 所示.
518 4.13.0.1. Example 4-23. 使用 quopri 模块
519 File: quopri-example-1.py
520 import quopri
521 import StringIO
522 # helpers (the quopri module only supports file-to-file conversion)
523 def encodestring(instring, tabs=0):
524 outfile = StringIO.StringIO()
525 quopri.encode(StringIO.StringIO(instring), outfile, tabs)
526 return outfile.getvalue()
527 def decodestring(instring):
528 outfile = StringIO.StringIO()
529 quopri.decode(StringIO.StringIO(instring), outfile)
530 return outfile.getvalue()
531 #
532 # try it out
533 MESSAGE = "? i ?a ? e ?!"
534 encoded_message = encodestring(MESSAGE)
535 decoded_message = decodestring(encoded_message)
536 print "original:", MESSAGE
537 print "encoded message:", repr(encoded_message)
538 print "decoded message:", decoded_message
539 original: ? i ?a ? e ?!
540 encoded message: '=E5 i =E5a =E4 e =F6!\012'
541 decoded message: ? i ?a ? e ?!
542 如 Example 4-23 所示, 非 U.S. 字符通过等号 (= ) 附加两个十六进制字符来
543 表示. 这里需要注意等号也是使用这样的方式( "=3D " )来表示的, 以及换行符
544 ( "=20 " ). 其他字符不会被改变. 所以如果你没有用太多的怪异字符的话, 编
545 码后字符串依然可读性很好.
546 (Europeans generally hate this encoding and strongly believe that certain
547 U.S. programmers deserve to be slapped in the head with a huge great fish
548 to the jolly music of Edward German....)
549 4.14. uu 模块
550 uu 编码体系用于将任意二进制数据转换为普通文本格式. 该格式在新闻组中很
551 流行, 但逐渐被 base64 编码取代.
552 uu 编码将每个 3 字节( 24 位)的数据组转换为 4 个可打印字符(每个字符 6
553 位), 使用从 chr(32) (空格) 到 chr(95) 的字符. uu 编码通常会使数据大小
554 增加 40% .
555 一个编码后的数据流以一个新行开始, 它包含文件的权限( Unix 格式)和文件
556 名, 以 end 行结尾:
557 begin 666 sample.jpg
558 M_]C_X 02D9)1@ ! 0 0 ! #_VP!# @&!@<&!0@'!P<)'0@*#!0-# L+
559 ...more lines like this...
560 end
561 uu 模块提供了两个函数: encode 和 decode .
562 encode(infile, outfile, filename) 函数从编码输入文件中的数据, 然后写入
563 到输出文件中. 如 Example 4-24 所示. infile 和 outfile 可以是文件名或文
564 件对象. filename 参数作为起始域的文件名写入.
565 4.14.0.1. Example 4-24. 使用 uu 模块编码二进制文件
566 File: uu-example-1.py
567 import uu
568 import os, sys
569 infile = "samples/sample.jpg"
570 uu.encode(infile, sys.stdout, os.path.basename(infile))
571 begin 666 sample.jpg
572 M_]C_X 02D9)1@ ! 0 0 ! #_VP!# @&!@<&!0@'!P<)"0@*#!0-# L+
573 M#!D2$P\4'1H?'AT:'!P@)"XG("(L(QP<*#<I+# Q-#0T'R<Y/3@R/"XS-#+_
574 MVP!# 0D)"0P+#!@-#1@R(1PA,C(R,C(R,C(R,C(R,C(R,C(R,C(R,C(R,C(R
575 M,C(R,C(R,C(R,C(R,C(R,C(R,C(R,C+_P 1" " ( # 2( A$! Q$!_\0
576 M'P 04! 0$! 0$ $" P0%!@<("0H+_\0 M1 @$# P($ P4%
577 decode(infile, outfile) 函数用来解码 uu 编码的数据. 同样地, 参数可以
578 是文件名也可以是文件对象. 如 Example 4-25 所示.
579 4.14.0.2. Example 4-25. 使用 uu 模块解码 uu 格式的文件
580 File: uu-example-2.py
581 import uu
582 import StringIO
583 infile = "samples/sample.uue"
584 outfile = "samples/sample.jpg"
585 #
586 # decode
587 fi = open(infile)
588 fo = StringIO.StringIO()
589 uu.decode(fi, fo)
590 #
591 # compare with original data file
592 data = open(outfile, "rb").read()
593 if fo.getvalue() == data:
594 print len(data), "bytes ok"
595 4.15. binascii 模块
596 binascii 提供了多个编码的支持函数, 包括 base64 , binhex , 以及 uu . 如
597 Example 4-26 所示.
598 2.0 及以后版本中, 你还可以使用它在二进制数据和十六进制字符串中相互转
599 换.
600 4.15.0.1. Example 4-26. 使用 binascii 模块
601 File: binascii-example-1.py
602 import binascii
603 text = "hello, mrs teal"
604 data = binascii.b2a_base64(text)
605 text = binascii.a2b_base64(data)
606 print text, "<=>", repr(data)
607 data = binascii.b2a_uu(text)
608 text = binascii.a2b_uu(data)
609 print text, "<=>", repr(data)
610 data = binascii.b2a_hqx(text)
611 text = binascii.a2b_hqx(data)[0]
612 print text, "<=>", repr(data)
613 # 2.0 and newer
614 data = binascii.b2a_hex(text)
615 text = binascii.a2b_hex(data)
616 print text, "<=>", repr(data)
617 hello, mrs teal <=> 'aGVsbG8sIG1ycyB0ZWFs\012'
618 hello, mrs teal <=> '/:&5L;&\\L(&UR<R!T96%L\012'
619 hello, mrs teal <=> 'D\'9XE\'mX)\'ebFb"dC@&X'
620 hello, mrs teal <=> '68656c6c6f2c206d7273207465616c'
1 5. 文件格式python标准库实例-5文件格式
2 o 5.1. 概览
3 o 5.2. xmllib 模块
4 o 5.3. xml.parsers.expat 模块
5 o 5.4. sgmllib 模块
6 o 5.5. htmllib 模块
7 o 5.6. htmlentitydefs 模块
8 o 5.7. formatter 模块
9 o 5.8. ConfigParser 模块
10 o 5.9. netrc 模块
11 o 5.10. shlex 模块
12 o 5.11. zipfile 模块
13 o 5.12. gzip 模块
14
15
16
17
18 5. 文件格式
19 5.1. 概览
20 本章将描述用于处理不同文件格式的模块.
21 5.1.1. Markup 语言
22 Python 提供了一些用于处理可扩展标记语言( Extensible Markup Language ,
23 XML ) 和超文本标记语言( Hypertext Markup Language , HTML )的扩展. Python
24 同样提供了对标准通用标记语言( Standard Generalized Markup Language ,
25 SGML )的支持.
26 所有这些格式都有着相同的结构, 因为 HTML 和 XML 都来自 SGML . 每个文档
27 都是由起始标签( start tags ), 结束标签( end tags ), 文本(又叫字符数据),
28 以及实体引用( entity references )构成:
29 <document name="sample.xml">
30 <header>This is a header</header>
31 <body>This is the body text. The text can contain
32 plain text ("character data"), tags, and
33 entities.
34 </body>
35 </document>
36 在这个例子中, <document> , <header> , 以及 <body> 是起始标签. 每个起始
37 标签都有一个对应的结束标签, 使用斜线 "/ " 标记. 起始标签可以包含多个
38 属性, 比如这里的 name 属性.
39 起始标签和它对应的结束标签中的任何东西被称为 元素( element ) . 这里
40 document 元素包含 header 和 body 两个元素.
41 " 是一个字符实体( character entity ). 字符实体用于在文本区域中表
42 示特殊的保留字符, 使用 & 指示. 这里它代表一个引号, 常见字符实体还有 "
43 < ( < ) " 和 " > ( > ) " .
44 虽然 XML , HTML , SGML 使用相同的结构块, 但它们还有一些不同点. 在 XML
45 中, 所有元素必须有起始和结束标签, 所有标签必须正确嵌套( well-formed ).
46 而且 XML 是区分大小写的, 所以 <document> 和 <Document> 是不同的元素类
47 型.
48 HTML 有很高灵活性, HTML 语法分析器一般会自动补全缺失标签; 例如, 当遇
49 到一个以 <P> 标签开始的新段落, 却没有对应结束标签, 语法分析器会自动添
50 加一个 </P> 标签. HTML 也是区分大小写的. 另一方面, XML 允许你定义任何
51 元素, 而 HTML 使用一些由 HTML 规范定义的固定元素.
52 SGML 有着更高的灵活性, 你可以使用自己的声明( declaration ) 定义源文件
53 如何转换到元素结构, DTD ( document type description , 文件类型定义)可
54 以用来检查结构并补全缺失标签. 技术上来说, HTML 和 XML 都是 SGML 应用,
55 有各自的 SGML 声明, 而且 HTML 有一个标准 DTD .
56 Python 提供了多个 makeup 语言分析器. 由于 SGML 是最灵活的格式, Python
57 的 sgmllib 事实上很简单. 它不会去处理 DTD , 不过你可以继承它来提供更
58 复杂的功能.
59 Python 的 HTML 支持基于 SGML 分析器. htmllib 将具体的格式输出工作交给
60 formatter 对象. formatter 模块包含一些标准格式化标志.
61 Python 的 XML 支持模块很复杂. 先前是只有与 sgmllib 类似的 xmllib , 后
62 来加入了更高级的 expat 模块(可选). 而最新版本中已经准备废弃 xmllib ,
63 启用 xml 包作为工具集.
64 5.1.2. 配置文件
65 ConfigParser 模块用于读取简单的配置文件, 类似 Windows 下的 INI 文件.
66 netrc 模块用于读取 .netrc 配置文件, shlex 模块用于读取类似 shell 脚本
67 语法的配置文件.
68 5.1.3. 压缩档案格式
69 Python 的标准库提供了对 GZIP 和 ZIP ( 2.0 及以后) 格式的支持. 基于
70 zlib 模块, gzip 和 zipfile 模块分别用来处理这类文件.
71 5.2. xmllib 模块
72 xmllib 已在当前版本中申明不支持.
73 xmlib 模块提供了一个简单的 XML 语法分析器, 使用正则表达式将 XML 数据
74 分离, 如 Example 5-1 所示. 语法分析器只对文档做基本的检查, 例如是否只
75 有一个顶层元素, 所有的标签是否匹配.
76 XML 数据一块一块地发送给 xmllib 分析器(例如在网路中传输的数据). 分析
77 器在遇到起始标签, 数据区域, 结束标签, 和实体的时候调用不同的方法.
78 如果你只是对某些标签感兴趣, 你可以定义特殊的 start_tag 和 end_tag 方
79 法, 这里 tag 是标签名称. 这些 start 函数使用它们对应标签的属性作为参
80 数调用(传递时为一个字典).
81 5.2.0.1. Example 5-1. 使用 xmllib 模块获取元素的信息
82 File: xmllib-example-1.py
83 import xmllib
84 class Parser(xmllib.XMLParser):
85 # get quotation number
86 def _ _init_ _(self, file=None):
87 xmllib.XMLParser._ _init_ _(self)
88 if file:
89 self.load(file)
90 def load(self, file):
91 while 1:
92 s = file.read(512)
93 if not s:
94 break
95 self.feed(s)
96 self.close()
97 def start_quotation(self, attrs):
98 print "id =>", attrs.get("id")
99 raise EOFError
100 try:
101 c = Parser()
102 c.load(open("samples/sample.xml"))
103 except EOFError:
104 pass
105 id => 031
106 Example 5-2 展示了一个简单(不完整)的内容输出引擎( rendering engine ).
107 分析器有一个元素堆栈( _ _tags ), 它连同文本片断传递给输出生成器. 生成
108 器会在 style 字典中查询当前标签的层次, 如果不存在, 它将根据样式表创建
109 一个新的样式描述.
110 5.2.0.2. Example 5-2. 使用 xmllib 模块
111 File: xmllib-example-2.py
112 import xmllib
113 import string, sys
114 STYLESHEET = {
115 # each element can contribute one or more style elements
116 "quotation": {"style": "italic"},
117 "lang": {"weight": "bold"},
118 "name": {"weight": "medium"},
119 }
120 class Parser(xmllib.XMLParser):
121 # a simple styling engine
122 def _ _init_ _(self, renderer):
123 xmllib.XMLParser._ _init_ _(self)
124 self._ _data = []
125 self._ _tags = []
126 self._ _renderer = renderer
127 def load(self, file):
128 while 1:
129 s = file.read(8192)
130 if not s:
131 break
132 self.feed(s)
133 self.close()
134 def handle_data(self, data):
135 self._ _data.append(data)
136 def unknown_starttag(self, tag, attrs):
137 if self._ _data:
138 text = string.join(self._ _data, "")
139 self._ _renderer.text(self._ _tags, text)
140 self._ _tags.append(tag)
141 self._ _data = []
142 def unknown_endtag(self, tag):
143 self._ _tags.pop()
144 if self._ _data:
145 text = string.join(self._ _data, "")
146 self._ _renderer.text(self._ _tags, text)
147 self._ _data = []
148 class DumbRenderer:
149 def _ _init_ _(self):
150 self.cache = {}
151 def text(self, tags, text):
152 # render text in the style given by the tag stack
153 tags = tuple(tags)
154 style = self.cache.get(tags)
155 if style is None:
156 # figure out a combined style
157 style = {}
158 for tag in tags:
159 s = STYLESHEET.get(tag)
160 if s:
161 style.update(s)
162 self.cache[tags] = style # update cache
163 # write to standard output
164 sys.stdout.write("%s =>\n" % style)
165 sys.stdout.write(" " + repr(text) + "\n")
166 #
167 # try it out
168 r = DumbRenderer()
169 c = Parser(r)
170 c.load(open("samples/sample.xml"))
171 {'style': 'italic'} =>
172 'I\'ve had a lot of developers come up to me and\012say,
173 "I haven\'t had this much fun in a long time. It sure
174 beats\012writing '
175 {'style': 'italic', 'weight': 'bold'} =>
176 'Cobol'
177 {'style': 'italic'} =>
178 '" -- '
179 {'style': 'italic', 'weight': 'medium'} =>
180 'James Gosling'
181 {'style': 'italic'} =>
182 ', on\012'
183 {'weight': 'bold'} =>
184 'Java'
185 {'style': 'italic'} =>
186 '.'
187 5.3. xml.parsers.expat 模块
188 (可选) xml.parsers.expat 模块是 James Clark's Expat XML parser 的接口.
189 Example 5-3 展示了这个功能完整且性能很好的语法分析器.
190 5.3.0.1. Example 5-3. 使用 xml.parsers.expat 模块
191 File: xml-parsers-expat-example-1.py
192 from xml.parsers import expat
193 class Parser:
194 def _ _init_ _(self):
195 self._parser = expat.ParserCreate()
196 self._parser.StartElementHandler = self.start
197 self._parser.EndElementHandler = self.end
198 self._parser.CharacterDataHandler = self.data
199 def feed(self, data):
200 self._parser.Parse(data, 0)
201 def close(self):
202 self._parser.Parse("", 1) # end of data
203 del self._parser # get rid of circular references
204 def start(self, tag, attrs):
205 print "START", repr(tag), attrs
206 def end(self, tag):
207 print "END", repr(tag)
208 def data(self, data):
209 print "DATA", repr(data)
210 p = Parser()
211 p.feed("<tag>data</tag>")
212 p.close()
213 START u'tag' {}
214 DATA u'data'
215 END u'tag'
216 注意即使你传入的是普通的文本, 这里的分析器仍然会返回 Unicode 字符串.
217 默认情况下, 分析器将源文本作为 UTF-8 解析. 如果要使用其他编码, 请确保
218 XML 文件包含 encoding 说明. 如 Example 5-4 所示.
219 5.3.0.2. Example 5-4. 使用 xml.parsers.expat 模块读取 ISO Latin-1 文
220 本
221 File: xml-parsers-expat-example-2.py
222 from xml.parsers import expat
223 class Parser:
224 def _ _init_ _(self):
225 self._parser = expat.ParserCreate()
226 self._parser.StartElementHandler = self.start
227 self._parser.EndElementHandler = self.end
228 self._parser.CharacterDataHandler = self.data
229 def feed(self, data):
230 self._parser.Parse(data, 0)
231 def close(self):
232 self._parser.Parse("", 1) # end of data
233 del self._parser # get rid of circular references
234 def start(self, tag, attrs):
235 print "START", repr(tag), attrs
236 def end(self, tag):
237 print "END", repr(tag)
238 def data(self, data):
239 print "DATA", repr(data)
240 p = Parser()
241 p.feed("""\
242 <?xml version='1.0' encoding='iso-8859-1'?>
243 <author>
244 <name>fredrik lundh</name>
245 <city>link?ping</city>
246 </author>
247 """
248 )
249 p.close()
250 START u'author' {}
251 DATA u'\012'
252 START u'name' {}
253 DATA u'fredrik lundh'
254 END u'name'
255 DATA u'\012'
256 START u'city' {}
257 DATA u'link\366ping'
258 END u'city'
259 DATA u'\012'
260 END u'author'
261 5.4. sgmllib 模块
262 sgmllib 模块, 提供了一个基本的 SGML 语法分析器. 它与 xmllib 分析器基
263 本相同, 但限制更少(而且不是很完善). 如 Example 5-5 所示.
264 和在 xmllib 中一样, 这个分析器在遇到起始标签, 数据区域, 结束标签以及
265 实体时调用内部方法. 如果你只是对某些标签感兴趣, 那么你可以定义特殊的
266 方法.
267 5.4.0.1. Example 5-5. 使用 sgmllib 模块提取 Title 元素
268 File: sgmllib-example-1.py
269 import sgmllib
270 import string
271 class FoundTitle(Exception):
272 pass
273 class ExtractTitle(sgmllib.SGMLParser):
274 def _ _init_ _(self, verbose=0):
275 sgmllib.SGMLParser._ _init_ _(self, verbose)
276 self.title = self.data = None
277 def handle_data(self, data):
278 if self.data is not None:
279 self.data.append(data)
280 def start_title(self, attrs):
281 self.data = []
282 def end_title(self):
283 self.title = string.join(self.data, "")
284 raise FoundTitle # abort parsing!
285 def extract(file):
286 # extract title from an HTML/SGML stream
287 p = ExtractTitle()
288 try:
289 while 1:
290 # read small chunks
291 s = file.read(512)
292 if not s:
293 break
294 p.feed(s)
295 p.close()
296 except FoundTitle:
297 return p.title
298 return None
299 #
300 # try it out
301 print "html", "=>", extract(open("samples/sample.htm"))
302 print "sgml", "=>", extract(open("samples/sample.sgm"))
303 html => A Title.
304 sgml => Quotations
305 重载 unknown_starttag 和 unknown_endtag 方法就可以处理所有的标签. 如
306 Example 5-6 所示.
307 5.4.0.2. Example 5-6. 使用 sgmllib 模块格式化 SGML 文档
308 File: sgmllib-example-2.py
309 import sgmllib
310 import cgi, sys
311 class PrettyPrinter(sgmllib.SGMLParser):
312 # A simple SGML pretty printer
313 def _ _init_ _(self):
314 # initialize base class
315 sgmllib.SGMLParser._ _init_ _(self)
316 self.flag = 0
317 def newline(self):
318 # force newline, if necessary
319 if self.flag:
320 sys.stdout.write("\n")
321 self.flag = 0
322 def unknown_starttag(self, tag, attrs):
323 # called for each start tag
324 # the attrs argument is a list of (attr, value)
325 # tuples. convert it to a string.
326 text = ""
327 for attr, value in attrs:
328 text = text + " %s='%s'" % (attr, cgi.escape(value))
329 self.newline()
330 sys.stdout.write("<%s%s>\n" % (tag, text))
331 def handle_data(self, text):
332 # called for each text section
333 sys.stdout.write(text)
334 self.flag = (text[-1:] != "\n")
335 def handle_entityref(self, text):
336 # called for each entity
337 sys.stdout.write("&%s;" % text)
338 def unknown_endtag(self, tag):
339 # called for each end tag
340 self.newline()
341 sys.stdout.write("<%s>" % tag)
342 #
343 # try it out
344 file = open("samples/sample.sgm")
345 p = PrettyPrinter()
346 p.feed(file.read())
347 p.close()
348 <chapter>
349 <title>
350 Quotations
351 <title>
352 <epigraph>
353 <attribution>
354 eff-bot, June 1997
355 <attribution>
356 <para>
357 <quote>
358 Nobody expects the Spanish Inquisition! Amongst
359 our weaponry are such diverse elements as fear, surprise,
360 ruthless efficiency, and an almost fanatical devotion to
361 Guido, and nice red uniforms — oh, damn!
362 <quote>
363 <para>
364 <epigraph>
365 <chapter>
366 Example 5-7 检查 SGML 文档是否是如 XML 那样 "正确格式化", 所有的元素
367 是否正确嵌套, 起始和结束标签是否匹配等.
368 我们使用列表保存所有起始标签, 然后检查每个结束标签是否匹配前个起始标
369 签. 最后确认到达文件末尾时没有未关闭的标签.
370 5.4.0.3. Example 5-7. 使用 sgmllib 模块检查格式
371 File: sgmllib-example-3.py
372 import sgmllib
373 class WellFormednessChecker(sgmllib.SGMLParser):
374 # check that an SGML document is 'well-formed'
375 # (in the XML sense).
376 def _ _init_ _(self, file=None):
377 sgmllib.SGMLParser._ _init_ _(self)
378 self.tags = []
379 if file:
380 self.load(file)
381 def load(self, file):
382 while 1:
383 s = file.read(8192)
384 if not s:
385 break
386 self.feed(s)
387 self.close()
388 def close(self):
389 sgmllib.SGMLParser.close(self)
390 if self.tags:
391 raise SyntaxError, "start tag %s not closed" % self.tags[-1]
392 def unknown_starttag(self, start, attrs):
393 self.tags.append(start)
394 def unknown_endtag(self, end):
395 start = self.tags.pop()
396 if end != start:
397 raise SyntaxError, "end tag %s does't match start tag %s" %\
398 (end, start)
399 try:
400 c = WellFormednessChecker()
401 c.load(open("samples/sample.htm"))
402 except SyntaxError:
403 raise # report error
404 else:
405 print "document is well-formed"
406 Traceback (innermost last):
407 ...
408 SyntaxError: end tag head does't match start tag meta
409 最后, Example 5-8 中的类可以用来过滤 HTML 和 SGML 文档. 继承这个类, 然
410 后实现 start 和 end 方法即可.
411 5.4.0.4. Example 5-8. 使用 sgmllib 模块过滤 SGML 文档
412 File: sgmllib-example-4.py
413 import sgmllib
414 import cgi, string, sys
415 class SGMLFilter(sgmllib.SGMLParser):
416 # sgml filter. override start/end to manipulate
417 # document elements
418 def _ _init_ _(self, outfile=None, infile=None):
419 sgmllib.SGMLParser._ _init_ _(self)
420 if not outfile:
421 outfile = sys.stdout
422 self.write = outfile.write
423 if infile:
424 self.load(infile)
425 def load(self, file):
426 while 1:
427 s = file.read(8192)
428 if not s:
429 break
430 self.feed(s)
431 self.close()
432 def handle_entityref(self, name):
433 self.write("&%s;" % name)
434 def handle_data(self, data):
435 self.write(cgi.escape(data))
436 def unknown_starttag(self, tag, attrs):
437 tag, attrs = self.start(tag, attrs)
438 if tag:
439 if not attrs:
440 self.write("<%s>" % tag)
441 else:
442 self.write("<%s" % tag)
443 for k, v in attrs:
444 self.write(" %s=%s" % (k, repr(v)))
445 self.write(">")
446 def unknown_endtag(self, tag):
447 tag = self.end(tag)
448 if tag:
449 self.write("</%s>" % tag)
450 def start(self, tag, attrs):
451 return tag, attrs # override
452 def end(self, tag):
453 return tag # override
454 class Filter(SGMLFilter):
455 def fixtag(self, tag):
456 if tag == "em":
457 tag = "i"
458 if tag == "string":
459 tag = "b"
460 return string.upper(tag)
461 def start(self, tag, attrs):
462 return self.fixtag(tag), attrs
463 def end(self, tag):
464 return self.fixtag(tag)
465 c = Filter()
466 c.load(open("samples/sample.htm"))
467 5.5. htmllib 模块
468 htmlib 模块包含了一个标签驱动的( tag-driven ) HTML 语法分析器, 它会将
469 数据发送至一个格式化对象. 如 Example 5-9 所示. 更多关于如何解析 HTML
470 的例子请参阅 formatter 模块.
471 5.5.0.1. Example 5-9. 使用 htmllib 模块
472 File: htmllib-example-1.py
473 import htmllib
474 import formatter
475 import string
476 class Parser(htmllib.HTMLParser):
477 # return a dictionary mapping anchor texts to lists
478 # of associated hyperlinks
479 def _ _init_ _(self, verbose=0):
480 self.anchors = {}
481 f = formatter.NullFormatter()
482 htmllib.HTMLParser._ _init_ _(self, f, verbose)
483 def anchor_bgn(self, href, name, type):
484 self.save_bgn()
485 self.anchor = href
486 def anchor_end(self):
487 text = string.strip(self.save_end())
488 if self.anchor and text:
489 self.anchors[text] = self.anchors.get(text, []) +
490 [self.anchor]
491 file = open("samples/sample.htm")
492 html = file.read()
493 file.close()
494 p = Parser()
495 p.feed(html)
496 p.close()
497 for k, v in p.anchors.items():
498 print k, "=>", v
499 print
500 link => ['http://www.python.org']
501 如果你只是想解析一个 HTML 文件, 而不是将它交给输出设备, 那么 sgmllib
502 模块会是更好的选择.
503 5.6. htmlentitydefs 模块
504 htmlentitydefs 模块包含一个由 HTML 中 ISO Latin-1 字符实体构成的字典.
505 如 Example 5-10 所示.
506 5.6.0.1. Example 5-10. 使用 htmlentitydefs 模块
507 File: htmlentitydefs-example-1.py
508 import htmlentitydefs
509 entities = htmlentitydefs.entitydefs
510 for entity in "amp", "quot", "copy", "yen":
511 print entity, "=", entities[entity]
512 amp = &
513 quot = "
514 copy = \302\251
515 yen = \302\245
516 Example 5-11 展示了如何将正则表达式与这个字典结合起来翻译字符串中的实
517 体 ( cgi.escape 的逆向操作).
518 5.6.0.2. Example 5-11. 使用 htmlentitydefs 模块翻译实体
519 File: htmlentitydefs-example-2.py
520 import htmlentitydefs
521 import re
522 import cgi
523 pattern = re.compile("&(\w+?);")
524 def descape_entity(m, defs=htmlentitydefs.entitydefs):
525 # callback: translate one entity to its ISO Latin value
526 try:
527 return defs[m.group(1)]
528 except KeyError:
529 return m.group(0) # use as is
530 def descape(string):
531 return pattern.sub(descape_entity, string)
532 print descape("<spam&eggs>")
533 print descape(cgi.escape("<spam&eggs>"))
534 <spam&eggs>
535 <spam&eggs>
536 最后, Example 5-12 展示了如何将 XML 保留字符和 ISO Latin-1 字符转换为
537 XML 字符串. 与 cgi.escape 相似, 但它会替换非 ASCII 字符.
538 5.6.0.3. Example 5-12. 转义 ISO Latin-1 实体
539 File: htmlentitydefs-example-3.py
540 import htmlentitydefs
541 import re, string
542 # this pattern matches substrings of reserved and non-ASCII characters
543 pattern = re.compile(r"[&<>\"\x80-\xff]+")
544 # create character map
545 entity_map = {}
546 for i in range(256):
547 entity_map[chr(i)] = "&%d;" % i
548 for entity, char in htmlentitydefs.entitydefs.items():
549 if entity_map.has_key(char):
550 entity_map[char] = "&%s;" % entity
551 def escape_entity(m, get=entity_map.get):
552 return string.join(map(get, m.group()), "")
553 def escape(string):
554 return pattern.sub(escape_entity, string)
555 print escape("<spam&eggs>")
556 print escape("\303\245 i \303\245a \303\244 e \303\266")
557 <spam&eggs>
558 å i åa ä e ö
559 5.7. formatter 模块
560 formatter 模块提供了一些可用于 htmllib 的格式类( formatter classes ).
561 这些类有两种, formatter 和 writer . formatter 将 HTML 解析器的标签和数
562 据流转换为适合输出设备的事件流( event stream ), 而 writer 将事件流输出
563 到设备上. 如 Example 5-13 所示.
564 大多情况下, 你可以使用 AbstractFormatter 类进行格式化. 它会根据不同的
565 格式化事件调用 writer 对象的方法. AbstractWriter 类在每次方法调用时打
566 印一条信息.
567 5.7.0.1. Example 5-13. 使用 formatter 模块将 HTML 转换为事件流
568 File: formatter-example-1.py
569 import formatter
570 import htmllib
571 w = formatter.AbstractWriter()
572 f = formatter.AbstractFormatter(w)
573 file = open("samples/sample.htm")
574 p = htmllib.HTMLParser(f)
575 p.feed(file.read())
576 p.close()
577 file.close()
578 send_paragraph(1)
579 new_font(('h1', 0, 1, 0))
580 send_flowing_data('A Chapter.')
581 send_line_break()
582 send_paragraph(1)
583 new_font(None)
584 send_flowing_data('Some text. Some more text. Some')
585 send_flowing_data(' ')
586 new_font((None, 1, None, None))
587 send_flowing_data('emphasized')
588 new_font(None)
589 send_flowing_data(' text. A')
590 send_flowing_data(' link')
591 send_flowing_data('[1]')
592 send_flowing_data('.')
593 formatter 模块还提供了 NullWriter 类, 它会将任何传递给它的事件忽略;
594 以及 DumbWriter 类, 它会将事件流转换为纯文本文档. 如 Example 5-14 所
595 示.
596 5.7.0.2. Example 5-14. 使用 formatter 模块将 HTML 转换为纯文本
597 File: formatter-example-2.py
598 import formatter
599 import htmllib
600 w = formatter.DumbWriter() # plain text
601 f = formatter.AbstractFormatter(w)
602 file = open("samples/sample.htm")
603 # print html body as plain text
604 p = htmllib.HTMLParser(f)
605 p.feed(file.read())
606 p.close()
607 file.close()
608 # print links
609 print
610 print
611 i = 1
612 for link in p.anchorlist:
613 print i, "=>", link
614 i = i + 1
615 A Chapter.
616 Some text. Some more text. Some emphasized text. A link[1].
617 1 => http://www.python.org
618 Example 5-15 提供了一个自定义的 Writer , 它继承自 DumbWriter 类, 会记
619 录当前字体样式并根据字体美化输出格式.
620 5.7.0.3. Example 5-15. 使用 formatter 模块自定义 Writer
621 File: formatter-example-3.py
622 import formatter
623 import htmllib, string
624 class Writer(formatter.DumbWriter):
625 def _ _init_ _(self):
626 formatter.DumbWriter._ _init_ _(self)
627 self.tag = ""
628 self.bold = self.italic = 0
629 self.fonts = []
630 def new_font(self, font):
631 if font is None:
632 font = self.fonts.pop()
633 self.tag, self.bold, self.italic = font
634 else:
635 self.fonts.append((self.tag, self.bold, self.italic))
636 tag, bold, italic, typewriter = font
637 if tag is not None:
638 self.tag = tag
639 if bold is not None:
640 self.bold = bold
641 if italic is not None:
642 self.italic = italic
643 def send_flowing_data(self, data):
644 if not data:
645 return
646 atbreak = self.atbreak or data[0] in string.whitespace
647 for word in string.split(data):
648 if atbreak:
649 self.file.write(" ")
650 if self.tag in ("h1", "h2", "h3"):
651 word = string.upper(word)
652 if self.bold:
653 word = "*" + word + "*"
654 if self.italic:
655 word = "_" + word + "_"
656 self.file.write(word)
657 atbreak = 1
658 self.atbreak = data[-1] in string.whitespace
659 w = Writer()
660 f = formatter.AbstractFormatter(w)
661 file = open("samples/sample.htm")
662 # print html body as plain text
663 p = htmllib.HTMLParser(f)
664 p.feed(file.read())
665 p.close()
666 _A_ _CHAPTER._
667 Some text. Some more text. Some *emphasized* text. A link[1].
668 5.8. ConfigParser 模块
669 ConfigParser 模块用于读取配置文件.
670 配置文件的格式与 Windows INI 文件类似, 可以包含一个或多个区域
671 ( section ), 每个区域可以有多个配置条目.
672 这里有个样例配置文件, 在 Example 5-16 用到了这个文件:
673 [book]
674 title: The Python Standard Library
675 author: Fredrik Lundh
676 email: fredrik@pythonware.com
677 version: 2.0-001115
678 [ematter]
679 pages: 250
680 [hardcopy]
681 pages: 350
682 Example 5-16 使用 ConfigParser 模块读取这个配制文件.
683 5.8.0.1. Example 5-16. 使用 ConfigParser 模块
684 File: configparser-example-1.py
685 import ConfigParser
686 import string
687 config = ConfigParser.ConfigParser()
688 config.read("samples/sample.ini")
689 # print summary
690 print
691 print string.upper(config.get("book", "title"))
692 print "by", config.get("book", "author"),
693 print "(" + config.get("book", "email") + ")"
694 print
695 print config.get("ematter", "pages"), "pages"
696 print
697 # dump entire config file
698 for section in config.sections():
699 print section
700 for option in config.options(section):
701 print " ", option, "=", config.get(section, option)
702 THE PYTHON STANDARD LIBRARY
703 by Fredrik Lundh (fredrik@pythonware.com)
704 250 pages
705 book
706 title = The Python Standard Library
707 email = fredrik@pythonware.com
708 author = Fredrik Lundh
709 version = 2.0-001115
710 _ _name_ _ = book
711 ematter
712 _ _name_ _ = ematter
713 pages = 250
714 hardcopy
715 _ _name_ _ = hardcopy
716 pages = 350
717 Python 2.0 以后, ConfigParser 模块也可以将配置数据写入文件, 如 Example
718 5-17 所示.
719 5.8.0.2. Example 5-17. 使用 ConfigParser 模块写入配置数据
720 File: configparser-example-2.py
721 import ConfigParser
722 import sys
723 config = ConfigParser.ConfigParser()
724 # set a number of parameters
725 config.add_section("book")
726 config.set("book", "title", "the python standard library")
727 config.set("book", "author", "fredrik lundh")
728 config.add_section("ematter")
729 config.set("ematter", "pages", 250)
730 # write to screen
731 config.write(sys.stdout)
732 [book]
733 title = the python standard library
734 author = fredrik lundh
735 [ematter]
736 pages = 250
737 5.9. netrc 模块
738 netrc 模块可以用来解析 .netrc 配置文件, 如 Example 5-18 所示. 该文件
739 用于在用户的 home 目录储存 FTP 用户名和密码. (别忘记设置这个文件的属
740 性为: "chmod 0600 ~/.netrc," 这样只有当前用户能访问).
741 5.9.0.1. Example 5-18. 使用 netrc 模块
742 File: netrc-example-1.py
743 import netrc
744 # default is $HOME/.netrc
745 info = netrc.netrc("samples/sample.netrc")
746 login, account, password = info.authenticators("secret.fbi")
747 print "login", "=>", repr(login)
748 print "account", "=>", repr(account)
749 print "password", "=>", repr(password)
750 login => 'mulder'
751 account => None
752 password => 'trustno1'
753 5.10. shlex 模块
754 shlex 模块为基于 Unix shell 语法的语言提供了一个简单的 lexer (也就是
755 tokenizer). 如 Example 5-19 所示.
756 5.10.0.1. Example 5-19. 使用 shlex 模块
757 File: shlex-example-1.py
758 import shlex
759 lexer = shlex.shlex(open("samples/sample.netrc", "r"))
760 lexer.wordchars = lexer.wordchars + "._"
761 while 1:
762 token = lexer.get_token()
763 if not token:
764 break
765 print repr(token)
766 'machine'
767 'secret.fbi'
768 'login'
769 'mulder'
770 'password'
771 'trustno1'
772 'machine'
773 'non.secret.fbi'
774 'login'
775 'scully'
776 'password'
777 'noway'
778 5.11. zipfile 模块
779 ( 2.0 新增) zipfile 模块可以用来读写 ZIP 格式.
780 5.11.1. 列出内容
781 使用 namelist 和 infolist 方法可以列出压缩档的内容, 前者返回由文件名
782 组成的列表, 后者返回由 ZipInfo 实例组成的列表. 如 Example 5-20 所示.
783 5.11.1.1. Example 5-20. 使用 zipfile 模块列出 ZIP 文档中的文件
784 File: zipfile-example-1.py
785 import zipfile
786 file = zipfile.ZipFile("samples/sample.zip", "r")
787 # list filenames
788 for name in file.namelist():
789 print name,
790 print
791 # list file information
792 for info in file.infolist():
793 print info.filename, info.date_time, info.file_size
794 sample.txt sample.jpg
795 sample.txt (1999, 9, 11, 20, 11, 8) 302
796 sample.jpg (1999, 9, 18, 16, 9, 44) 4762
797 5.11.2. 从 ZIP 文件中读取数据
798 调用 read 方法就可以从 ZIP 文档中读取数据. 它接受一个文件名作为参数,
799 返回字符串. 如 Example 5-21 所示.
800 5.11.2.1. Example 5-21. 使用 zipfile 模块从 ZIP 文件中读取数据
801 File: zipfile-example-2.py
802 import zipfile
803 file = zipfile.ZipFile("samples/sample.zip", "r")
804 for name in file.namelist():
805 data = file.read(name)
806 print name, len(data), repr(data[:10])
807 sample.txt 302 'We will pe'
808 sample.jpg 4762 '\377\330\377\340\000\020JFIF'
809 5.11.3. 向 ZIP 文件写入数据
810 向压缩档加入文件很简单, 将文件名, 文件在 ZIP 档中的名称传递给 write
811 方法即可.
812 Example 5-22 将 samples 目录中的所有文件打包为一个 ZIP 文件.
813 5.11.3.1. Example 5-22. 使用 zipfile 模块将文件储存在 ZIP 文件里
814 File: zipfile-example-3.py
815 import zipfile
816 import glob, os
817 # open the zip file for writing, and write stuff to it
818 file = zipfile.ZipFile("test.zip", "w")
819 for name in glob.glob("samples/*"):
820 file.write(name, os.path.basename(name), zipfile.ZIP_DEFLATED)
821 file.close()
822 # open the file again, to see what's in it
823 file = zipfile.ZipFile("test.zip", "r")
824 for info in file.infolist():
825 print info.filename, info.date_time, info.file_size,
826 info.compress_size
827 sample.wav (1999, 8, 15, 21, 26, 46) 13260 10985
828 sample.jpg (1999, 9, 18, 16, 9, 44) 4762 4626
829 sample.au (1999, 7, 18, 20, 57, 34) 1676 1103
830 ...
831 write 方法的第三个可选参数用于控制是否使用压缩. 默认为
832 zipfile.ZIP_STORED , 意味着只是将数据储存在档案里而不进行任何压缩. 如
833 果安装了 zlib 模块, 那么就可以使用 zipfile.ZIP_DEFLATED 进行压缩.
834 zipfile 模块也可以向档案中添加字符串. 不过, 这需要一点技巧, 你需要创
835 建一个 ZipInfo 实例, 并正确配置它. Example 5-23 提供了一种简单的解决办
836 法.
837 5.11.3.2. Example 5-23. 使用 zipfile 模块在 ZIP 文件中储存字符串
838 File: zipfile-example-4.py
839 import zipfile
840 import glob, os, time
841 file = zipfile.ZipFile("test.zip", "w")
842 now = time.localtime(time.time())[:6]
843 for name in ("life", "of", "brian"):
844 info = zipfile.ZipInfo(name)
845 info.date_time = now
846 info.compress_type = zipfile.ZIP_DEFLATED
847 file.writestr(info, name*1000)
848 file.close()
849 # open the file again, to see what's in it
850 file = zipfile.ZipFile("test.zip", "r")
851 for info in file.infolist():
852 print info.filename, info.date_time, info.file_size,
853 info.compress_size
854 life (2000, 12, 1, 0, 12, 1) 4000 26
855 of (2000, 12, 1, 0, 12, 1) 2000 18
856 brian (2000, 12, 1, 0, 12, 1) 5000 31
857 5.12. gzip 模块
858 gzip 模块用来读写 gzip 格式的压缩文件, 如 Example 5-24 所示.
859 5.12.0.1. Example 5-24. 使用 gzip 模块读取压缩文件
860 File: gzip-example-1.py
861 import gzip
862 file = gzip.GzipFile("samples/sample.gz")
863 print file.read()
864 Well it certainly looks as though we're in for
865 a splendid afternoon's sport in this the 127th
866 Upperclass Twit of the Year Show.
867 标准的实现并不支持 seek 和 tell 方法. 不过 Example 5-25 可以解决这个
868 问题.
869 5.12.0.2. Example 5-25. 给 gzip 模块添加 seek/tell 支持
870 File: gzip-example-2.py
871 import gzip
872 class gzipFile(gzip.GzipFile):
873 # adds seek/tell support to GzipFile
874 offset = 0
875 def read(self, size=None):
876 data = gzip.GzipFile.read(self, size)
877 self.offset = self.offset + len(data)
878 return data
879 def seek(self, offset, whence=0):
880 # figure out new position (we can only seek forwards)
881 if whence == 0:
882 position = offset
883 elif whence == 1:
884 position = self.offset + offset
885 else:
886 raise IOError, "Illegal argument"
887 if position < self.offset:
888 raise IOError, "Cannot seek backwards"
889 # skip forward, in 16k blocks
890 while position > self.offset:
891 if not self.read(min(position - self.offset, 16384)):
892 break
893 def tell(self):
894 return self.offset
895 #
896 # try it
897 file = gzipFile("samples/sample.gz")
898 file.seek(80)
899 print file.read()
900 this the 127th
901 Upperclass Twit of the Year Show.
1 6. 邮件和新闻消息处理python标准库实例-6邮件和新闻消息处理
2 o 6.1. 概览
3 o 6.2. rfc822 模块
4 o 6.3. mimetools 模块
5 o 6.4. MimeWriter 模块
6 o 6.5. mailbox 模块
7 o 6.6. mailcap 模块
8 o 6.7. mimetypes 模块
9 o 6.8. packmail 模块
10 o 6.9. mimify 模块
11 o 6.10. multifile 模块
12
13
14 6. 邮件和新闻消息处理
15 "To be removed from our list of future commercial postings by [SOME]
16 PUBLISHING COMPANY an Annual Charge of Ninety Five dollars is required.
17 Just send $95.00 with your Name, Address and Name of the Newsgroup to be
18 removed from our list."
19 - Newsgroup spammer, July 1996
20 "想要退出 '某' 宣传公司的未来商业广告列表吗, 您需要付 95 美元. 只要您
21 支付95 美元, 并且告诉我们您的姓名, 地址, 和需要退出的新闻组, 我们就会
22 把您从列表中移除."
23 - 新闻组垃圾发送者, 1996 年 7 月
24 6.1. 概览
25 Python 有大量用于处理邮件和新闻组的模块, 其中包括了许多常见的邮件格
26 式.
27 6.2. rfc822 模块
28 rfc822 模块包括了一个邮件和新闻组的解析器 (也可用于其它符合 RFC 822
29 标准的消息, 比如 HTTP 头).
30 通常, RFC 822 格式的消息包含一些标头字段, 后面至少有一个空行, 然后是信
31 息主体.
32 For example, here's a short mail message. The first five lines make up
33 the message header, and the actual message (a single line, in this case)
34 follows after an empty line:
35 例如这里的邮件信息. 前五行组成了消息标头, 隔一个空行后是消息主体.
36 Message-Id: <20001114144603.00abb310@oreilly.com>
37 Date: Tue, 14 Nov 2000 14:55:07 -0500
38 To: "Fredrik Lundh" <fredrik@effbot.org>
39 From: Frank
40 Subject: Re: python library book!
41 Where is it?
42 消息解析器读取标头字段后会返回一个以消息标头为键的类字典对象, 如
43 Example 6-1 所示.
44 6.2.0.1. Example 6-1. 使用 rfc822 模块
45 File: rfc822-example-1.py
46 import rfc822
47 file = open("samples/sample.eml")
48 message = rfc822.Message(file)
49 for k, v in message.items():
50 print k, "=", v
51 print len(file.read()), "bytes in body"
52 subject = Re: python library book!
53 from = "Frank" <your@editor>
54 message-id = <20001114144603.00abb310@oreilly.com>
55 to = "Fredrik Lundh" <fredrik@effbot.org>
56 date = Tue, 14 Nov 2000 14:55:07 -0500
57 25 bytes in body
58 消息对象( message object )还提供了一些用于解析地址字段和数据的, 如
59 Example 6-2 所示.
60 6.2.0.2. Example 6-2. 使用 rfc822 模块解析标头字段
61 File: rfc822-example-2.py
62 import rfc822
63 file = open("samples/sample.eml")
64 message = rfc822.Message(file)
65 print message.getdate("date")
66 print message.getaddr("from")
67 print message.getaddrlist("to")
68 (2000, 11, 14, 14, 55, 7, 0, 0, 0)
69 ('Frank', 'your@editor')
70 [('Fredrik Lundh', 'fredrik@effbot.org')]
71 地址字段被解析为 (实际名称, 邮件地址) 这样的元组. 数据字段被解析为 9
72 元时间元组, 可以使用 time 模块处理.
73 6.3. mimetools 模块
74 多用途因特网邮件扩展 ( Multipurpose Internet Mail Extensions, MIME ) 标
75 准定义了如何在 RFC 822 格式的消息中储存非 ASCII 文本, 图像以及其它数
76 据.
77 mimetools 模块包含一些读写 MIME 信息的工具. 它还提供了一个类似 rfc822
78 模块中 Message 的类, 用于处理 MIME 编码的信息. 如 Example 6-3 所示.
79 6.3.0.1. Example 6-3. 使用 mimetools 模块
80 File: mimetools-example-1.py
81 import mimetools
82 file = open("samples/sample.msg")
83 msg = mimetools.Message(file)
84 print "type", "=>", msg.gettype()
85 print "encoding", "=>", msg.getencoding()
86 print "plist", "=>", msg.getplist()
87 print "header", "=>"
88 for k, v in msg.items():
89 print " ", k, "=", v
90 type => text/plain
91 encoding => 7bit
92 plist => ['charset="iso-8859-1"']
93 header =>
94 mime-version = 1.0
95 content-type = text/plain;
96 charset="iso-8859-1"
97 to = effbot@spam.egg
98 date = Fri, 15 Oct 1999 03:21:15 -0400
99 content-transfer-encoding = 7bit
100 from = "Fredrik Lundh" <fredrik@pythonware.com>
101 subject = By the way...
102 ...
103 6.4. MimeWriter 模块
104 MimeWriter 模块用于生成符合 MIME 邮件标准的 "多部分" 的信息, 如
105 Example 6-4 所示.
106 6.4.0.1. Example 6-4. 使用 MimeWriter 模块
107 File: mimewriter-example-1.py
108 import MimeWriter
109 # data encoders
110 # 数据编码
111 import quopri
112 import base64
113 import StringIO
114 import sys
115 TEXT = """
116 here comes the image you asked for. hope
117 it's what you expected.
118 </F>"""
119 FILE = "samples/sample.jpg"
120 file = sys.stdout
121 #
122 # create a mime multipart writer instance
123 mime = MimeWriter.MimeWriter(file)
124 mime.addheader("Mime-Version", "1.0")
125 mime.startmultipartbody("mixed")
126 # add a text message
127 # 加入文字信息
128 part = mime.nextpart()
129 part.addheader("Content-Transfer-Encoding", "quoted-printable")
130 part.startbody("text/plain")
131 quopri.encode(StringIO.StringIO(TEXT), file, 0)
132 # add an image
133 # 加入图片
134 part = mime.nextpart()
135 part.addheader("Content-Transfer-Encoding", "base64")
136 part.startbody("image/jpeg")
137 base64.encode(open(FILE, "rb"), file)
138 mime.lastpart()
139 输出结果如下:
140 Content-Type: multipart/mixed;
141 boundary='host.1.-852461.936831373.130.24813'
142 --host.1.-852461.936831373.130.24813
143 Content-Type: text/plain
144 Context-Transfer-Encoding: quoted-printable
145 here comes the image you asked for. hope
146 it's what you expected.
147 </F>
148 --host.1.-852461.936831373.130.24813
149 Content-Type: image/jpeg
150 Context-Transfer-Encoding: base64
151 /9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UH
152 Rof
153 HBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhM
154 jIy
155 ...
156 1e5vLrSYbJnEVpEgjCLx5mPU0qsVK0UaxjdNlS+1U6pfzTR8IzEhj2HrVG6m8m18xc8cI
157 KSC
158 tCuFyC746j/Cq2pTia4WztfmKjGBXTCmo6IUpt==
159 --host.1.-852461.936831373.130.24813--
160 [Example 6-5 #eg-6-5 ] 使用辅助类储存每个子部分.
161 6.4.0.2. Example 6-5. MimeWriter 模块的辅助类
162 File: mimewriter-example-2.py
163 import MimeWriter
164 import string, StringIO, sys
165 import re, quopri, base64
166 # check if string contains non-ascii characters
167 must_quote = re.compile("[\177-\377]").search
168 #
169 # encoders
170 def encode_quoted_printable(infile, outfile):
171 quopri.encode(infile, outfile, 0)
172 class Writer:
173 def _ _init_ _(self, file=None, blurb=None):
174 if file is None:
175 file = sys.stdout
176 self.file = file
177 self.mime = MimeWriter.MimeWriter(file)
178 self.mime.addheader("Mime-Version", "1.0")
179 file = self.mime.startmultipartbody("mixed")
180 if blurb:
181 file.write(blurb)
182 def close(self):
183 "End of message"
184 self.mime.lastpart()
185 self.mime = self.file = None
186 def write(self, data, mimetype="text/plain"):
187 "Write data from string or file to message"
188 # data is either an opened file or a string
189 if type(data) is type(""):
190 file = StringIO.StringIO(data)
191 else:
192 file = data
193 data = None
194 part = self.mime.nextpart()
195 typ, subtyp = string.split(mimetype, "/", 1)
196 if typ == "text":
197 # text data
198 encoding = "quoted-printable"
199 encoder = lambda i, o: quopri.encode(i, o, 0)
200 if data and not must_quote(data):
201 # copy, don't encode
202 encoding = "7bit"
203 encoder = None
204 else:
205 # binary data (image, audio, application, ...)
206 encoding = "base64"
207 encoder = base64.encode
208 #
209 # write part headers
210 if encoding:
211 part.addheader("Content-Transfer-Encoding", encoding)
212 part.startbody(mimetype)
213 #
214 # write part body
215 if encoder:
216 encoder(file, self.file)
217 elif data:
218 self.file.write(data)
219 else:
220 while 1:
221 data = infile.read(16384)
222 if not data:
223 break
224 outfile.write(data)
225 #
226 # try it out
227 BLURB = "if you can read this, your mailer is not MIME-aware\n"
228 mime = Writer(sys.stdout, BLURB)
229 # add a text message
230 mime.write("""\
231 here comes the image you asked for. hope
232 it's what you expected.
233 """, "text/plain")
234 # add an image
235 mime.write(open("samples/sample.jpg", "rb"), "image/jpeg")
236 mime.close()
237 6.5. mailbox 模块
238 mailbox 模块用来处理各种不同类型的邮箱格式, 如 Example 6-6 所示. 大部
239 分邮箱格式使用文本文件储存纯 RFC 822 信息, 用分割行区别不同的信息.
240 6.5.0.1. Example 6-6. 使用 mailbox 模块
241 File: mailbox-example-1.py
242 import mailbox
243 mb = mailbox.UnixMailbox(open("/var/spool/mail/effbot"))
244 while 1:
245 msg = mb.next()
246 if not msg:
247 break
248 for k, v in msg.items():
249 print k, "=", v
250 body = msg.fp.read()
251 print len(body), "bytes in body"
252 subject = for he's a ...
253 message-id = <199910150027.CAA03202@spam.egg>
254 received = (from fredrik@pythonware.com)
255 by spam.egg (8.8.7/8.8.5) id CAA03202
256 for effbot; Fri, 15 Oct 1999 02:27:36 +0200
257 from = Fredrik Lundh <fredrik@pythonware.com>
258 date = Fri, 15 Oct 1999 12:35:36 +0200
259 to = effbot@spam.egg
260 1295 bytes in body
261 6.6. mailcap 模块
262 mailcap 模块用于处理 mailcap 文件, 该文件指定了不同的文档格式的处理方
263 法( Unix 系统下). 如 Example 6-7 所示.
264 6.6.0.1. Example 6-7. 使用 mailcap 模块获得 Capability 字典
265 File: mailcap-example-1.py
266 import mailcap
267 caps = mailcap.getcaps()
268 for k, v in caps.items():
269 print k, "=", v
270 image/* = [{'view': 'pilview'}]
271 application/postscript = [{'view': 'ghostview'}]
272 Example 6-7 中, 系统使用 pilview 来预览( view )所有类型的图片, 使用
273 ghostscript viewer 预览 PostScript 文档. Example 6-8 展示了如何使用
274 mailcap 获得特定操作的命令.
275 6.6.0.2. Example 6-8. 使用 mailcap 模块获得打开
276 File: mailcap-example-2.py
277 import mailcap
278 caps = mailcap.getcaps()
279 command, info = mailcap.findmatch(
280 caps, "image/jpeg", "view", "samples/sample.jpg"
281 )
282 print command
283 pilview samples/sample.jpg
284 6.7. mimetypes 模块
285 mimetypes 模块可以判断给定 url ( uniform resource locator , 统一资源定
286 位符) 的 MIME 类型. 它基于一个内建的表, 还可能搜索 Apache 和 Netscape
287 的配置文件. 如 Example 6-9 所示.
288 6.7.0.1. Example 6-9. 使用 mimetypes 模块
289 File: mimetypes-example-1.py
290 import mimetypes
291 import glob, urllib
292 for file in glob.glob("samples/*"):
293 url = urllib.pathname2url(file)
294 print file, mimetypes.guess_type(url)
295 samples\sample.au ('audio/basic', None)
296 samples\sample.ini (None, None)
297 samples\sample.jpg ('image/jpeg', None)
298 samples\sample.msg (None, None)
299 samples\sample.tar ('application/x-tar', None)
300 samples\sample.tgz ('application/x-tar', 'gzip')
301 samples\sample.txt ('text/plain', None)
302 samples\sample.wav ('audio/x-wav', None)
303 samples\sample.zip ('application/zip', None)
304 6.8. packmail 模块
305 (已废弃) packmail 模块可以用来创建 Unix shell 档案. 如果安装了合适的工
306 具, 那么你就可以直接通过运行来解开这样的档案. Example 6-10 展示了如何
307 打包单个文件, Example 6-11 则打包了整个目录树.
308 6.8.0.1. Example 6-10. 使用 packmail 打包单个文件
309 File: packmail-example-1.py
310 import packmail
311 import sys
312 packmail.pack(sys.stdout, "samples/sample.txt", "sample.txt")
313 echo sample.txt
314 sed "s/^X//" >sample.txt <<"!"
315 XWe will perhaps eventually be writing only small
316 Xmodules, which are identified by name as they are
317 Xused to build larger ones, so that devices like
318 Xindentation, rather than delimiters, might become
319 Xfeasible for expressing local structure in the
320 Xsource language.
321 X -- Donald E. Knuth, December 1974
322 !
323 ====Example 6-11. 使用 packmail 打包整个目录树===[eg-6-11]
324 File: packmail-example-2.py
325 import packmail
326 import sys
327 packmail.packtree(sys.stdout, "samples")
328 注意, 这个模块不能处理二进制文件, 例如声音或者图像文件.
329 6.9. mimify 模块
330 mimify 模块用于在 MIME 编码的文本信息和普通文本信息(例如 ISO Latin 1
331 文本)间相互转换. 它可以用作命令行工具, 或是特定邮件代理的转换过滤器:
332 $ mimify.py -e raw-message mime-message
333 $ mimify.py -d mime-message raw-message
334 作为模块使用, 如 Example 6-12 所示.
335 6.9.0.1. Example 6-12. 使用 mimify 模块解码信息
336 File: mimify-example-1.py
337 import mimify
338 import sys
339 mimify.unmimify("samples/sample.msg", sys.stdout, 1)
340 这里是一个包含两部分的 MIME 信息, 一个是引用的可打印信息, 另个是
341 base64 编码信息. unmimify 的第三个参数决定是否自动解码 base64 编码的
342 部分:
343 MIME-Version: 1.0
344 Content-Type: multipart/mixed; boundary='boundary'
345 this is a multipart sample file. the two
346 parts both contain ISO Latin 1 text, with
347 different encoding techniques.
348 --boundary
349 Content-Type: text/plain
350 Content-Transfer-Encoding: quoted-printable
351 sillmj=F6lke! blindstyre! medisterkorv!
352 --boundary
353 Content-Type: text/plain
354 Content-Transfer-Encoding: base64
355 a29tIG5lciBiYXJhLCBvbSBkdSB09nJzIQ==
356 --boundary--
357 解码结果如下 (可读性相对来说更好些):
358 MIME-Version: 1.0
359 Content-Type: multipart/mixed; boundary= 'boundary'
360 this is a multipart sample file. the two
361 parts both contain ISO Latin 1 text, with
362 different encoding techniques.
363 --boundary
364 Content-Type: text/plain
365 sillmj?lke! blindstyre! medisterkorv!
366 --boundary
367 Content-Type: text/plain
368 kom ner bara, om du t?rs!
369 Example 6-13 展示了如何编码信息.
370 6.9.0.2. Example 6-13. 使用 mimify 模块编码信息
371 File: mimify-example-2.py
372 import mimify
373 import StringIO, sys
374 #
375 # decode message into a string buffer
376 file = StringIO.StringIO()
377 mimify.unmimify("samples/sample.msg", file, 1)
378 #
379 # encode message from string buffer
380 file.seek(0) # rewind
381 mimify.mimify(file, sys.stdout)
382 6.10. multifile 模块
383 multifile 模块允许你将一个多部分的 MIME 信息的每部分作为单独的文件处
384 理. 如 Example 6-14 所示.
385 6.10.0.1. Example 6-14. 使用 multifile 模块
386 File: multifile-example-1.py
387 import multifile
388 import cgi, rfc822
389 infile = open("samples/sample.msg")
390 message = rfc822.Message(infile)
391 # print parsed header
392 for k, v in message.items():
393 print k, "=", v
394 # use cgi support function to parse content-type header
395 type, params = cgi.parse_header(message["content-type"])
396 if type[:10] == "multipart/":
397 # multipart message
398 boundary = params["boundary"]
399 file = multifile.MultiFile(infile)
400 file.push(boundary)
401 while file.next():
402 submessage = rfc822.Message(file)
403 # print submessage
404 print "-" * 68
405 for k, v in submessage.items():
406 print k, "=", v
407 print
408 print file.read()
409 file.pop()
410 else:
411 # plain message
412 print infile.read()
1 7. 网络协议python标准库实例-7网络协议
2 o 7.1. 概览
3 o 7.2. socket 模块
4 o 7.3. select 模块
5 o 7.4. asyncore 模块
6 o 7.5. asynchat 模块
7 o 7.6. urllib 模块
8 o 7.7. urlparse 模块
9 o 7.8. cookie 模块
10 o 7.9. robotparser 模块
11 o 7.10. ftplib 模块
12 o 7.11. gopherlib 模块
13 o 7.12. httplib 模块
14 o 7.13. poplib 模块
15 o 7.14. imaplib 模块
16 o 7.15. smtplib 模块
17 o 7.16. telnetlib 模块
18 o 7.17. nntplib 模块
19 o 7.18. SocketServer 模块
20 o 7.19. BaseHTTPServer 模块
21 o 7.20. SimpleHTTPServer 模块
22 o 7.21. CGIHTTPServer 模块
23 o 7.22. cgi 模块
24 o 7.23. webbrowser 模块
25
26
27
28 7. 网络协议
29 "Increasingly, people seem to misinterpret complexity as sophistication,
30 which is baffling - the incomprehensible should cause suspicion rather
31 than admiration. Possibly this trend results from a mistaken belief that
32 using a somewhat mysterious device confers an aura of power on the user."
33 - Niklaus Wirth
34 7.1. 概览
35 本章描述了 Python 的 socket 协议支持以及其他建立在 socket 模块上的网
36 络模块. 这些包含了对大多流行 Internet 协议客户端的支持, 以及一些可用
37 来实现 Internet 服务器的框架.
38 对于那些本章中的底层的例子, 我将使用两个协议作为样例: Internet Time
39 Protocol ( Internet 时间协议 ) 以及 Hypertext Transfer Protocol (超文
40 本传输协议, HTTP 协议).
41 7.1.1. Internet 时间协议
42 Internet 时间协议 ( RFC 868, Postel 和 Harrenstien, 1983) 可以让一个网
43 络客户端获得一个服务器的当前时间.
44 因为这个协议是轻量级的, 许多 Unix 系统(但不是所有)都提供了这个服务.
45 它可能是最简单的网络协议了. 服务器等待连接请求并在连接后返回当前时间
46 ( 4 字节整数, 自从 1900 年 1 月 1 日到当前的秒数).
47 协议很简单, 这里我们提供规格书给大家:
48 File: rfc868.txt
49 Network Working Group J. Postel -
50 ISI
51 Request for Comments: 868 K. Harrenstien - SRI
52 May
53 1983
54 Time Protocol
55 This RFC specifies a standard for the ARPA Internet community. Hosts on
56 the ARPA Internet that choose to implement a Time Protocol are expected
57 to adopt and implement this standard.
58 本 RFC 规范提供了一个 ARPA Internet community 上的标准.
59 在 ARPA Internet 上的所有主机应当采用并实现这个标准.
60 This protocol provides a site-independent, machine readable date and
61 time. The Time service sends back to the originating source the time in
62 seconds since midnight on January first 1900.
63 此协议提供了一个独立于站点的, 机器可读的日期和时间信息.
64 时间服务返回的是从 1900 年 1 月 1 日午夜到现在的秒数.
65 One motivation arises from the fact that not all systems have a
66 date/time clock, and all are subject to occasional human or machine
67 error. The use of time-servers makes it possible to quickly confirm or
68 correct a system's idea of the time, by making a brief poll of several
69 independent sites on the network.
70 设计这个协议的一个重要目的在于, 网络上的一些主机并没有时钟,
71 这有可能导致人工或者机器错误. 我们可以依靠时间服务器快速确认或者修改
72 一个系统的时间.
73 This protocol may be used either above the Transmission Control Protocol
74 (TCP) or above the User Datagram Protocol (UDP).
75 该协议可以用在 TCP 协议或是 UDP 协议上.
76 When used via TCP the time service works as follows:
77 通过 TCP 访问时间服务器的步骤:
78 * S: Listen on port 37 (45 octal).
79 * U: Connect to port 37.
80 * S: Send the time as a 32 bit binary number.
81 * U: Receive the time.
82 * U: Close the connection.
83 * S: Close the connection.
84 * S: 监听 37 ( 45 的八进制) 端口.
85 * U: 连接 37 端口.
86 * S: 将时间作为 32 位二进制数字发送.
87 * U: 接收时间.
88 * U: 关闭连接.
89 * S: 关闭连接.
90 The server listens for a connection on port 37. When the connection
91 is established, the server returns a 32-bit time value and closes the
92 connection. If the server is unable to determine the time at its
93 site, it should either refuse the connection or close it without
94 sending anything.
95 服务器在 37 端口监听. 当连接建立的时候, 服务器返回一个 32 位的数字
96 值
97 并关闭连接. 如果服务器自己无法决定当前时间, 那么它应该拒绝这个连接
98 或者
99 不发送任何数据立即关闭连接.
100 When used via UDP the time service works as follows:
101 通过 TCP 访问时间服务器的步骤:
102 S: Listen on port 37 (45 octal).
103 U: Send an empty datagram to port 37.
104 S: Receive the empty datagram.
105 S: Send a datagram containing the time as a 32 bit binary number.
106 U: Receive the time datagram.
107 S: 监听 37 ( 45 的八进制) 端口.
108 U: 发送空数据报文到 37 端口.
109 S: 接受空报文.
110 S: 发送包含时间( 32 位二进制数字 )的报文.
111 U: 接受时间报文.
112 The server listens for a datagram on port 37. When a datagram
113 arrives, the server returns a datagram containing the 32-bit time
114 value. If the server is unable to determine the time at its site, it
115 should discard the arriving datagram and make no reply.
116 服务器在 37 端口监听报文. 当报文到达时, 服务器返回包含 32 位时间值
117 的报文. 如果服务器无法决定当前时间, 那么它应该丢弃到达的报文,
118 不做任何回复.
119 The Time
120 时间
121 The time is the number of seconds since 00:00 (midnight) 1 January 1900
122 GMT, such that the time 1 is 12:00:01 am on 1 January 1900 GMT; this
123 base will serve until the year 2036.
124 时间是自 1900 年 1 月 1 日 0 时到当前的秒数,
125 这个协议标准会一直服务到2036 年. 到时候数字不够用再说.
126 For example:
127 the time 2,208,988,800 corresponds to 00:00 1 Jan 1970 GMT,
128 2,398,291,200 corresponds to 00:00 1 Jan 1976 GMT,
129 2,524,521,600 corresponds to 00:00 1 Jan 1980 GMT,
130 2,629,584,000 corresponds to 00:00 1 May 1983 GMT,
131 and -1,297,728,000 corresponds to 00:00 17 Nov 1858 GMT.
132 例如:
133 时间值 2,208,988,800 对应 to 00:00 1 Jan 1970 GMT,
134 2,398,291,200 对应 to 00:00 1 Jan 1976 GMT,
135 2,524,521,600 对应 to 00:00 1 Jan 1980 GMT,
136 2,629,584,000 对应 to 00:00 1 May 1983 GMT,
137 最后 -1,297,728,000 对应 to 00:00 17 Nov 1858 GMT.
138 RFC868.txt Translated By Andelf(gt: andelf@gmail.com )
139 非商业用途, 转载请保留作者信息. Thx.
140 7.1.2. HTTP 协议
141 超文本传输协议 ( HTTP, RFC 2616 ) 是另个完全不同的东西. 最近的格式说明
142 书( Version 1.1 )超过了 100 页.
143 从它最简单的格式来看, 这个协议是很简单的. 客户端发送如下的请求到服务
144 器, 请求一个文件:
145 GET /hello.txt HTTP/1.0
146 Host: hostname
147 User-Agent: name
148 [optional request body , 可选的请求正文]
149 服务器返回对应的响应:
150 HTTP/1.0 200 OK
151 Content-Type: text/plain
152 Content-Length: 7
153 Hello
154 请求和响应的 headers (报头)一般会包含更多的域, 但是请求 header 中的
155 Host 域/字段是必须提供的.
156 header 行使用 "\r\n " 分割, 而且 header 后必须有一个空行, 即使没有正
157 文 (请求和响应都必须符合这条规则).
158 剩下的 HTTP 协议格式说明书细节, 例如内容协商, 缓存机制, 保持连接, 等
159 等, 请参阅 Hypertext TransferProtocol - HTTP/1.1
160 ( http://www.w3.org/Protocols ).
161 7.2. socket 模块
162 socket 模块实现了到 socket 通讯层的接口. 你可以使用该模块创建客户端或
163 是服务器的 socket .
164 我们首先以一个客户端为例, Example 7-1 中的客户端连接到一个时间协议服务
165 器, 读取 4 字节的返回数据, 并把它转换为一个时间值.
166 7.2.0.1. Example 7-1. 使用 socket 模块实现一个时间客户端
167 File: socket-example-1.py
168 import socket
169 import struct, time
170 # server
171 HOST = "www.python.org"
172 PORT = 37
173 # reference time (in seconds since 1900-01-01 00:00:00)
174 TIME1970 = 2208988800L # 1970-01-01 00:00:00
175 # connect to server
176 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
177 s.connect((HOST, PORT))
178 # read 4 bytes, and convert to time value
179 t = s.recv(4)
180 t = struct.unpack("!I", t)[0]
181 t = int(t - TIME1970)
182 s.close()
183 # print results
184 print "server time is", time.ctime(t)
185 print "local clock is", int(time.time()) - t, "seconds off"
186 server time is Sat Oct 09 16:42:36 1999
187 local clock is 8 seconds off
188 socket 工厂函数( factory function )根据给定类型(该例子中为 Internet
189 stream socket , 即就是 TCP socket )创建一个新的 socket . connect 方法
190 尝试将这个 socket 连接到指定服务器上. 成功后, 就可以使用 recv 方法读
191 取数据.
192 创建一个服务器 socket 使用的是相同的方法, 不过这里不是连接到服务器,
193 而是将 socket bind (绑定)到本机的一个端口上, 告诉它去监听连接请求, 然
194 后尽快处理每个到达的请求.
195 Example 7-2 创建了一个时间服务器, 绑定到本机的 8037 端口( 1024 前的所
196 有端口是为系统服务保留的, Unix 系统下访问它们你必须要有 root 权限).
197 7.2.0.2. Example 7-2. 使用 socket 模块实现一个时间服务器
198 File: socket-example-2.py
199 import socket
200 import struct, time
201 # user-accessible port
202 PORT = 8037
203 # reference time
204 TIME1970 = 2208988800L
205 # establish server
206 service = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
207 service.bind(("", PORT))
208 service.listen(1)
209 print "listening on port", PORT
210 while 1:
211 # serve forever
212 channel, info = service.accept()
213 print "connection from", info
214 t = int(time.time()) + TIME1970
215 t = struct.pack("!I", t)
216 channel.send(t) # send timestamp
217 channel.close() # disconnect
218 listening on port 8037
219 connection from ('127.0.0.1', 1469)
220 connection from ('127.0.0.1', 1470)
221 ...
222 listen 函数的调用告诉 socket 我们期望接受连接. 参数代表连接的队列(用
223 于在程序没有处理前保持连接)大小. 最后 accept 循环将当前时间返回给每个
224 连接的客户端.
225 注意这里的 accept 函数返回一个新的 socket 对象, 这个对象是直接连接到
226 客户端的. 而原 socket 只是用来保持连接; 所有后来的数据传输操作都使用
227 新的 socket .
228 我们可以使用 Example 7-3 , ( Example 7-1 的通用化版本)来测试这个服务
229 器, .
230 7.2.0.3. Example 7-3. 一个时间协议客户端
231 File: timeclient.py
232 import socket
233 import struct, sys, time
234 # default server
235 host = "localhost"
236 port = 8037
237 # reference time (in seconds since 1900-01-01 00:00:00)
238 TIME1970 = 2208988800L # 1970-01-01 00:00:00
239 def gettime(host, port):
240 # fetch time buffer from stream server
241 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
242 s.connect((host, port))
243 t = s.recv(4)
244 s.close()
245 t = struct.unpack("!I", t)[0]
246 return int(t - TIME1970)
247 if _ _name_ _ == "_ _main_ _":
248 # command-line utility
249 if sys.argv[1:]:
250 host = sys.argv[1]
251 if sys.argv[2:]:
252 port = int(sys.argv[2])
253 else:
254 port = 37 # default for public servers
255 t = gettime(host, port)
256 print "server time is", time.ctime(t)
257 print "local clock is", int(time.time()) - t, "seconds off"
258 server time is Sat Oct 09 16:58:50 1999
259 local clock is 0 seconds off
260 Example 7-3 所示的脚本也可以作为模块使用; 你只需要导入 timeclient 模
261 块, 然后调用它的 gettime 函数.
262 目前为止, 我们已经使用了流( TCP ) socket . 时间协议还提到了 UDP sockets
263 (报文). 流 socket 的工作模式和电话线类似; 你会知道在远端是否有人拿起
264 接听器, 在对方挂断的时候你也会注意到. 相比之下, 发送报文更像是在一间
265 黑屋子里大声喊. 可能某人会在那里, 但你只有在他回复的时候才会知道.
266 如 Example 7-4 所示, 你不需要在通过报文 socket 发送数据时连接远程机器.
267 只需使用 sendto 方法, 它接受数据和接收者地址作为参数. 读取报文的时候
268 使用 recvfrom 方法.
269 7.2.0.4. Example 7-4. 使用 socket 模块实现一个报文时间客户端
270 File: socket-example-4.py
271 import socket
272 import struct, time
273 # server
274 HOST = "localhost"
275 PORT = 8037
276 # reference time (in seconds since 1900-01-01 00:00:00)
277 TIME1970 = 2208988800L # 1970-01-01 00:00:00
278 # connect to server
279 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
280 # send empty packet
281 s.sendto("", (HOST, PORT))
282 # read 4 bytes from server, and convert to time value
283 t, server = s.recvfrom(4)
284 t = struct.unpack("!I", t)[0]
285 t = int(t - TIME1970)
286 s.close()
287 print "server time is", time.ctime(t)
288 print "local clock is", int(time.time()) - t, "seconds off"
289 server time is Sat Oct 09 16:42:36 1999
290 local clock is 8 seconds off
291 这里的 recvfrom 返回两个值: 数据和发送者的地址. 后者用于发送回复数据.
292 Example 7-5 展示了对应的服务器代码.
293 Example 7-5. 使用 socket 模块实现一个报文时间服务器
294 File: socket-example-5.py
295 import socket
296 import struct, time
297 # user-accessible port
298 PORT = 8037
299 # reference time
300 TIME1970 = 2208988800L
301 # establish server
302 service = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
303 service.bind(("", PORT))
304 print "listening on port", PORT
305 while 1:
306 # serve forever
307 data, client = service.recvfrom(0)
308 print "connection from", client
309 t = int(time.time()) + TIME1970
310 t = struct.pack("!I", t)
311 service.sendto(t, client) # send timestamp
312 listening on port 8037
313 connection from ('127.0.0.1', 1469)
314 connection from ('127.0.0.1', 1470)
315 ...
316 最主要的不同在于服务器使用 bind 来分配一个已知端口给 socket , 根据
317 recvfrom 函数返回的地址向客户端发送数据.
318 7.3. select 模块
319 select 模块允许你检查一个或多个 socket , 管道, 以及其他流兼容对象所接
320 受的数据, 如 Example 7-6 所示.
321 你可以将一个或更多 socket 传递给 select 函数, 然后等待它们状态改变(可
322 读, 可写, 或是发送错误信号):
323 • 如果某人在调用了 listen 函数后连接, 当远端数据到达时, socket 就
324 成为可读的(这意味着 accept 不会阻塞). 或者是 socket 被关闭或重
325 置时(在此情况下, recv 会返回一个空字符串).
326 • 当非阻塞调用 connect 方法后建立连接或是数据可以被写入到 socket
327 时, socket 就成为可写的.
328 • 当非阻塞调用 connect 方法后连接失败后, socket 会发出一个错误信
329 号.
330 7.3.0.1. Example 7-6. 使用 select 模块等待经 socket 发送的数据
331 File: select-example-1.py
332 import select
333 import socket
334 import time
335 PORT = 8037
336 TIME1970 = 2208988800L
337 service = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
338 service.bind(("", PORT))
339 service.listen(1)
340 print "listening on port", PORT
341 while 1:
342 is_readable = [service]
343 is_writable = []
344 is_error = []
345 r, w, e = select.select(is_readable, is_writable, is_error, 1.0)
346 if r:
347 channel, info = service.accept()
348 print "connection from", info
349 t = int(time.time()) + TIME1970
350 t = chr(t>>24&255) + chr(t>>16&255) + chr(t>>8&255) + chr(t&255)
351 channel.send(t) # send timestamp
352 channel.close() # disconnect
353 else:
354 print "still waiting"
355 listening on port 8037
356 still waiting
357 still waiting
358 connection from ('127.0.0.1', 1469)
359 still waiting
360 connection from ('127.0.0.1', 1470)
361 ...
362 在 Example 7-6 中, 我们等待监听 socket 变成可读状态, 这代表有一个连接
363 请求到达. 我们用和之前一样的方法处理 channel socket , 因为它不可能因为
364 等待 4 字节而填充网络缓冲区. 如果你需要向客户端发送大量的数据, 那么你
365 应该在循环的顶端把数据加入到 is_writable 列表中, 并且只在 select 允许
366 的情况下写入.
367 如果你设置 socket 为非阻塞 模式(通过调用 setblocking 方法), 那么你就
368 可以使用 select 来等待 socket 连接. 不过 asyncore 模块(参见下一节)提
369 供了一个强大的框架, 它自动为你处理好了这一切. 所以我不准备在这里多说
370 什么, 看下一节吧.
371 7.4. asyncore 模块
372 asyncore 模块提供了一个 "反馈性的( reactive )" socket 实现. 该模块允许
373 你定义特定过程完成后所执行的代码, 而不是创建 socket 对象, 调用它们的
374 方法. 你只需要继承 dispatcher 类, 然后重载如下方法 (可以选择重载某一
375 个或多个)就可以实现异步的 socket 处理器.
376 • handle_connect : 一个连接成功建立后被调用.
377 • handle_expt : 连接失败后被调用.
378 • handle_accept : 连接请求建立到一个监听 socket 上时被调用. 回调
379 时( callback )应该使用 accept 方法来获得客户端 socket .
380 • handle_read : 有来自 socket 的数据等待读取时被调用. 回调时应该
381 使用 recv 方法来获得数据.
382 • handle_write : socket 可以写入数据的时候被调用. 使用 send 方法写
383 入数据.
384 • handle_close : 当 socket 被关闭或复位时被调用.
385 • handle_error(type, value, traceback) 在任何一个回调函数发生
386 Python 错误时被调用. 默认的实现会打印跟踪返回消息到
387 sys.stdout .
388 Example 7-7 展示了一个时间客户端, 和 socket 模块中的那个类似.
389 7.4.0.1. Example 7-7. 使用 asyncore 模块从时间服务器获得时间
390 File: asyncore-example-1.py
391 import asyncore
392 import socket, time
393 # reference time (in seconds since 1900-01-01 00:00:00)
394 TIME1970 = 2208988800L # 1970-01-01 00:00:00
395 class TimeRequest(asyncore.dispatcher):
396 # time requestor (as defined in RFC 868)
397 def _ _init_ _(self, host, port=37):
398 asyncore.dispatcher._ _init_ _(self)
399 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
400 self.connect((host, port))
401 def writable(self):
402 return 0 # don't have anything to write
403 def handle_connect(self):
404 pass # connection succeeded
405 def handle_expt(self):
406 self.close() # connection failed, shutdown
407 def handle_read(self):
408 # get local time
409 here = int(time.time()) + TIME1970
410 # get and unpack server time
411 s = self.recv(4)
412 there = ord(s[3]) + (ord(s[2])<<8) + (ord(s[1])<<16) +
413 (ord(s[0])<<24L)
414 self.adjust_time(int(here - there))
415 self.handle_close() # we don't expect more data
416 def handle_close(self):
417 self.close()
418 def adjust_time(self, delta):
419 # override this method!
420 print "time difference is", delta
421 #
422 # try it out
423 request = TimeRequest("www.python.org")
424 asyncore.loop()
425 log: adding channel <TimeRequest at 8cbe90>
426 time difference is 28
427 log: closing channel 192:<TimeRequest connected at 8cbe90>
428 如果你不想记录任何信息, 那么你可以在你的 dispatcher 类里重载 log 方
429 法.
430 Example 7-8 展示了对应的时间服务器. 注意这里它使用了两个 dispatcher
431 子类, 一个用于监听 socket , 另个用于与客户端通讯.
432 7.4.0.2. Example 7-8. 使用 asyncore 模块实现时间服务器
433 File: asyncore-example-2.py
434 import asyncore
435 import socket, time
436 # reference time
437 TIME1970 = 2208988800L
438 class TimeChannel(asyncore.dispatcher):
439 def handle_write(self):
440 t = int(time.time()) + TIME1970
441 t = chr(t>>24&255) + chr(t>>16&255) + chr(t>>8&255) + chr(t&255)
442 self.send(t)
443 self.close()
444 class TimeServer(asyncore.dispatcher):
445 def _ _init_ _(self, port=37):
446 self.port = port
447 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
448 self.bind(("", port))
449 self.listen(5)
450 print "listening on port", self.port
451 def handle_accept(self):
452 channel, addr = self.accept()
453 TimeChannel(channel)
454 server = TimeServer(8037)
455 asyncore.loop()
456 log: adding channel <TimeServer at 8cb940>
457 listening on port 8037
458 log: adding channel <TimeChannel at 8b2fd0>
459 log: closing channel 52:<TimeChannel connected at 8b2fd0>
460 除了 dispatcher 外, 这个模块还包含一个 dispatcher_with_send 类. 你可
461 以使用这个类发送大量的数据而不会阻塞网络通讯缓冲区.
462 Example 7-9 中的模块通过继承 dispatcher_with_send 类定义了一个
463 AsyncHTTP 类. 当你创建一个它的实例后, 它会发出一个 HTTP GET 请求并把
464 接受到的数据发送到一个 "consumer" 目标对象
465 7.4.0.3. Example 7-9. 使用 asyncore 模块发送 HTTP 请求
466 File: SimpleAsyncHTTP.py
467 import asyncore
468 import string, socket
469 import StringIO
470 import mimetools, urlparse
471 class AsyncHTTP(asyncore.dispatcher_with_send):
472 # HTTP requester
473 def _ _init_ _(self, uri, consumer):
474 asyncore.dispatcher_with_send._ _init_ _(self)
475 self.uri = uri
476 self.consumer = consumer
477 # turn the uri into a valid request
478 scheme, host, path, params, query, fragment =
479 urlparse.urlparse(uri)
480 assert scheme == "http", "only supports HTTP requests"
481 try:
482 host, port = string.split(host, ":", 1)
483 port = int(port)
484 except (TypeError, ValueError):
485 port = 80 # default port
486 if not path:
487 path = "/"
488 if params:
489 path = path + ";" + params
490 if query:
491 path = path + "?" + query
492 self.request = "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n" % (path,
493 host)
494 self.host = host
495 self.port = port
496 self.status = None
497 self.header = None
498 self.data = ""
499 # get things going!
500 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
501 self.connect((host, port))
502 def handle_connect(self):
503 # connection succeeded
504 self.send(self.request)
505 def handle_expt(self):
506 # connection failed; notify consumer (status is None)
507 self.close()
508 try:
509 http_header = self.consumer.http_header
510 except AttributeError:
511 pass
512 else:
513 http_header(self)
514 def handle_read(self):
515 data = self.recv(2048)
516 if not self.header:
517 self.data = self.data + data
518 try:
519 i = string.index(self.data, "\r\n\r\n")
520 except ValueError:
521 return # continue
522 else:
523 # parse header
524 fp = StringIO.StringIO(self.data[:i+4])
525 # status line is "HTTP/version status message"
526 status = fp.readline()
527 self.status = string.split(status, " ", 2)
528 # followed by a rfc822-style message header
529 self.header = mimetools.Message(fp)
530 # followed by a newline, and the payload (if any)
531 data = self.data[i+4:]
532 self.data = ""
533 # notify consumer (status is non-zero)
534 try:
535 http_header = self.consumer.http_header
536 except AttributeError:
537 pass
538 else:
539 http_header(self)
540 if not self.connected:
541 return # channel was closed by consumer
542 self.consumer.feed(data)
543 def handle_close(self):
544 self.consumer.close()
545 self.close()
546 Example 7-10 中的小脚本展示了如何使用这个类.
547 7.4.0.4. Example 7-10. 使用 SimpleAsyncHTTP 类
548 File: asyncore-example-3.py
549 import SimpleAsyncHTTP
550 import asyncore
551 class DummyConsumer:
552 size = 0
553 def http_header(self, request):
554 # handle header
555 if request.status is None:
556 print "connection failed"
557 else:
558 print "status", "=>", request.status
559 for key, value in request.header.items():
560 print key, "=", value
561 def feed(self, data):
562 # handle incoming data
563 self.size = self.size + len(data)
564 def close(self):
565 # end of data
566 print self.size, "bytes in body"
567 #
568 # try it out
569 consumer = DummyConsumer()
570 request = SimpleAsyncHTTP.AsyncHTTP(
571 "http://www.pythonware.com",
572 consumer
573 )
574 asyncore.loop()
575 log: adding channel <AsyncHTTP at 8e2850>
576 status => ['HTTP/1.1', '200', 'OK\015\012']
577 server = Apache/Unix (Unix)
578 content-type = text/html
579 content-length = 3730
580 ...
581 3730 bytes in body
582 log: closing channel 156:<AsyncHTTP connected at 8e2850>
583 这里的 consumer 接口设计时是为了与 htmllib 和 xmllib 分析器兼容的, 这
584 样你就可以直接方便地解析 HTML 或是 XML 数据. http_header 方法是可选的;
585 如果没有定义它, 那么它将被忽略.
586 Example 7-10 的一个问题是它不能很好地处理重定向资源. Example 7-11 加入
587 了一个额外的 consumer 层, 它可以很好地处理重定向.
588 7.4.0.5. Example 7-11. 使用 SimpleAsyncHTTP 类处理重定向
589 File: asyncore-example-4.py
590 import SimpleAsyncHTTP
591 import asyncore
592 class DummyConsumer:
593 size = 0
594 def http_header(self, request):
595 # handle header
596 if request.status is None:
597 print "connection failed"
598 else:
599 print "status", "=>", request.status
600 for key, value in request.header.items():
601 print key, "=", value
602 def feed(self, data):
603 # handle incoming data
604 self.size = self.size + len(data)
605 def close(self):
606 # end of data
607 print self.size, "bytes in body"
608 class RedirectingConsumer:
609 def _ _init_ _(self, consumer):
610 self.consumer = consumer
611 def http_header(self, request):
612 # handle header
613 if request.status is None or\
614 request.status[1] not in ("301", "302"):
615 try:
616 http_header = self.consumer.http_header
617 except AttributeError:
618 pass
619 else:
620 return http_header(request)
621 else:
622 # redirect!
623 uri = request.header["location"]
624 print "redirecting to", uri, "..."
625 request.close()
626 SimpleAsyncHTTP.AsyncHTTP(uri, self)
627 def feed(self, data):
628 self.consumer.feed(data)
629 def close(self):
630 self.consumer.close()
631 #
632 # try it out
633 consumer = RedirectingConsumer(DummyConsumer())
634 request = SimpleAsyncHTTP.AsyncHTTP(
635 "http://www.pythonware.com/library",
636 consumer
637 )
638 asyncore.loop()
639 log: adding channel <AsyncHTTP at 8e64b0>
640 redirecting to http://www.pythonware.com/library/ ...
641 log: closing channel 48:<AsyncHTTP connected at 8e64b0>
642 log: adding channel <AsyncHTTP at 8ea790>
643 status => ['HTTP/1.1', '200', 'OK\015\012']
644 server = Apache/Unix (Unix)
645 content-type = text/html
646 content-length = 387
647 ...
648 387 bytes in body
649 log: closing channel 236:<AsyncHTTP connected at 8ea790>
650 如果服务器返回状态 301 (永久重定向) 或者是 302 (临时重定向), 重定向的
651 consumer 会关闭当前请求并向新地址发出新请求. 所有对 consumer 的其他调
652 用传递给原来的 consumer .
653 7.5. asynchat 模块
654 asynchat 模块是对 asyncore 的一个扩展. 它提供对面向行( line-oriented )
655 的协议的额外支持. 它还提供了增强的缓冲区支持(通过 push 方法和
656 "producer" 机制.
657 Example 7-12 实现了一个很小的 HTTP 服务器. 它只是简单地返回包含 HTTP
658 请求信息的 HTML 文档(浏览器窗口出现的输出).
659 7.5.0.1. Example 7-12. 使用 asynchat 模块实现一个迷你 HTTP 服务器
660 File: asynchat-example-1.py
661 import asyncore, asynchat
662 import os, socket, string
663 PORT = 8000
664 class HTTPChannel(asynchat.async_chat):
665 def _ _init_ _(self, server, sock, addr):
666 asynchat.async_chat._ _init_ _(self, sock)
667 self.set_terminator("\r\n")
668 self.request = None
669 self.data = ""
670 self.shutdown = 0
671 def collect_incoming_data(self, data):
672 self.data = self.data + data
673 def found_terminator(self):
674 if not self.request:
675 # got the request line
676 self.request = string.split(self.data, None, 2)
677 if len(self.request) != 3:
678 self.shutdown = 1
679 else:
680 self.push("HTTP/1.0 200 OK\r\n")
681 self.push("Content-type: text/html\r\n")
682 self.push("\r\n")
683 self.data = self.data + "\r\n"
684 self.set_terminator("\r\n\r\n") # look for end of headers
685 else:
686 # return payload.
687 self.push("<html><body><pre>\r\n")
688 self.push(self.data)
689 self.push("</pre></body></html>\r\n")
690 self.close_when_done()
691 class HTTPServer(asyncore.dispatcher):
692 def _ _init_ _(self, port):
693 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
694 self.bind(("", port))
695 self.listen(5)
696 def handle_accept(self):
697 conn, addr = self.accept()
698 HTTPChannel(self, conn, addr)
699 #
700 # try it out
701 s = HTTPServer(PORT)
702 print "serving at port", PORT, "..."
703 asyncore.loop()
704 GET / HTTP/1.1
705 Accept: */*
706 Accept-Language: en, sv
707 Accept-Encoding: gzip, deflate
708 User-Agent: Mozilla/4.0 (compatible; Bruce/1.0)
709 Host: localhost:8000
710 Connection: Keep-Alive
711 producer 接口允许你传入( "push" )太大以至于无法在内存中储存的对象.
712 asyncore 在需要更多数据的时候自动调用 producer 的 more 方法. 另外, 它
713 使用一个空字符串标记文件的末尾.
714 Example 7-13 实现了一个很简单的基于文件的 HTTP 服务器, 它使用了一个简
715 单的 FileProducer 类来从文件中读取数据, 每次只读取几 kb .
716 7.5.0.2. Example 7-13. 使用 asynchat 模块实现一个简单的 HTTP 服务器
717 File: asynchat-example-2.py
718 import asyncore, asynchat
719 import os, socket, string, sys
720 import StringIO, mimetools
721 ROOT = "."
722 PORT = 8000
723 class HTTPChannel(asynchat.async_chat):
724 def _ _init_ _(self, server, sock, addr):
725 asynchat.async_chat._ _init_ _(self, sock)
726 self.server = server
727 self.set_terminator("\r\n\r\n")
728 self.header = None
729 self.data = ""
730 self.shutdown = 0
731 def collect_incoming_data(self, data):
732 self.data = self.data + data
733 if len(self.data) > 16384:
734 # limit the header size to prevent attacks
735 self.shutdown = 1
736 def found_terminator(self):
737 if not self.header:
738 # parse http header
739 fp = StringIO.StringIO(self.data)
740 request = string.split(fp.readline(), None, 2)
741 if len(request) != 3:
742 # badly formed request; just shut down
743 self.shutdown = 1
744 else:
745 # parse message header
746 self.header = mimetools.Message(fp)
747 self.set_terminator("\r\n")
748 self.server.handle_request(
749 self, request[0], request[1], self.header
750 )
751 self.close_when_done()
752 self.data = ""
753 else:
754 pass # ignore body data, for now
755 def pushstatus(self, status, explanation="OK"):
756 self.push("HTTP/1.0 %d %s\r\n" % (status, explanation))
757 class FileProducer:
758 # a producer that reads data from a file object
759 def _ _init_ _(self, file):
760 self.file = file
761 def more(self):
762 if self.file:
763 data = self.file.read(2048)
764 if data:
765 return data
766 self.file = None
767 return ""
768 class HTTPServer(asyncore.dispatcher):
769 def _ _init_ _(self, port=None, request=None):
770 if not port:
771 port = 80
772 self.port = port
773 if request:
774 self.handle_request = request # external request handler
775 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
776 self.bind(("", port))
777 self.listen(5)
778 def handle_accept(self):
779 conn, addr = self.accept()
780 HTTPChannel(self, conn, addr)
781 def handle_request(self, channel, method, path, header):
782 try:
783 # this is not safe!
784 while path[:1] == "/":
785 path = path[1:]
786 filename = os.path.join(ROOT, path)
787 print path, "=>", filename
788 file = open(filename, "r")
789 except IOError:
790 channel.pushstatus(404, "Not found")
791 channel.push("Content-type: text/html\r\n")
792 channel.push("\r\n")
793 channel.push("<html><body>File not
794 found.</body></html>\r\n")
795 else:
796 channel.pushstatus(200, "OK")
797 channel.push("Content-type: text/html\r\n")
798 channel.push("\r\n")
799 channel.push_with_producer(FileProducer(file))
800 #
801 # try it out
802 s = HTTPServer(PORT)
803 print "serving at port", PORT
804 asyncore.loop()
805 serving at port 8000
806 log: adding channel <HTTPServer at 8e54d0>
807 log: adding channel <HTTPChannel at 8e64a0>
808 samples/sample.htm => .\samples/sample.htm
809 log: closing channel 96:<HTTPChannel connected at 8e64a0>
810 7.6. urllib 模块
811 urlib 模块为 HTTP , FTP , 以及 gopher 提供了一个统一的客户端接口. 它会
812 自动地根据 URL 选择合适的协议处理器.
813 从 URL 获取数据是非常简单的. 只需要调用 urlopen 方法, 然后从返回的流
814 对象中读取数据即可, 如 Example 7-14 所示.
815 7.6.0.1. Example 7-14. 使用 urllib 模块获取远程资源
816 File: urllib-example-1.py
817 import urllib
818 fp = urllib.urlopen("http://www.python.org")
819 op = open("out.html", "wb")
820 n = 0
821 while 1:
822 s = fp.read(8192)
823 if not s:
824 break
825 op.write(s)
826 n = n + len(s)
827 fp.close()
828 op.close()
829 for k, v in fp.headers.items():
830 print k, "=", v
831 print "copied", n, "bytes from", fp.url
832 server = Apache/1.3.6 (Unix)
833 content-type = text/html
834 accept-ranges = bytes
835 date = Mon, 11 Oct 1999 20:11:40 GMT
836 connection = close
837 etag = "741e9-7870-37f356bf"
838 content-length = 30832
839 last-modified = Thu, 30 Sep 1999 12:25:35 GMT
840 copied 30832 bytes from http://www.python.org
841 这个流对象提供了一些非标准的属性. headers 是一个 Message 对象(在
842 mimetools 模块中定义), url 是实际的 URL . 后者会根据服务器的重定向而更
843 新.
844 urlopen 函数实际上是一个辅助函数, 它会创建一个 FancyURLopener 类的实
845 例并调用它的 open 方法. 你也可以继承这个类来完成特殊的行为. 例如
846 Example 7-15 中的类会自动地在必要时登陆服务器.
847 7.6.0.2. Example 7-15. 用 urllib 模块实现自动身份验证
848 File: urllib-example-3.py
849 import urllib
850 class myURLOpener(urllib.FancyURLopener):
851 # read an URL, with automatic HTTP authentication
852 def setpasswd(self, user, passwd):
853 self._ _user = user
854 self._ _passwd = passwd
855 def prompt_user_passwd(self, host, realm):
856 return self._ _user, self._ _passwd
857 urlopener = myURLOpener()
858 urlopener.setpasswd("mulder", "trustno1")
859 fp = urlopener.open("http://www.secretlabs.com")
860 print fp.read()
861 7.7. urlparse 模块
862 urlparse 模块包含用于处理 URL 的函数, 可以在 URL 和平台特定的文件名间
863 相互转换. 如 Example 7-16 所示.
864 7.7.0.1. Example 7-16. 使用 urlparse 模块
865 File: urlparse-example-1.py
866 import urlparse
867 print urlparse.urlparse("http://host/path;params?query#fragment")
868 ('http', 'host', '/path', 'params', 'query', 'fragment')
869 一个常见用途就是把 HTTP URL 分割为主机名和路径组件(一个 HTTP 请求会涉
870 及到主机名以及请求路径), 如 Example 7-17 所示.
871 7.7.0.2. Example 7-17. 使用 urlparse 模块处理 HTTP 定位器( HTTP
872 Locators )
873 File: urlparse-example-2.py
874 import urlparse
875 scheme, host, path, params, query, fragment =\
876 urlparse.urlparse("http://host/path;params?query#fragment")
877 if scheme == "http":
878 print "host", "=>", host
879 if params:
880 path = path + ";" + params
881 if query:
882 path = path + "?" + query
883 print "path", "=>", path
884 host => host
885 path => /path;params?query
886 Example 7-18 展示了如何使用 urlunparse 函数将各组成部分合并回一个
887 URL .
888 7.7.0.3. Example 7-18. 使用 urlparse 模块处理 HTTP 定位器( HTTP
889 Locators )
890 File: urlparse-example-3.py
891 import urlparse
892 scheme, host, path, params, query, fragment =\
893 urlparse.urlparse("http://host/path;params?query#fragment")
894 if scheme == "http":
895 print "host", "=>", host
896 print "path", "=>", urlparse.urlunparse(
897 (None, None, path, params, query, None)
898 )
899 host => host
900 path => /path;params?query
901 Example 7-19 使用 urljoin 函数将绝对路径和相对路径组合起来.
902 7.7.0.4. Example 7-19. 使用 urlparse 模块组合相对定位器
903 File: urlparse-example-4.py
904 import urlparse
905 base = "http://spam.egg/my/little/pony"
906 for path in "/index", "goldfish", "../black/cat":
907 print path, "=>", urlparse.urljoin(base, path)
908 /index => http://spam.egg/index
909 goldfish => http://spam.egg/my/little/goldfish
910 ../black/cat => http://spam.egg/my/black/cat
911 7.8. cookie 模块
912 (2.0 中新增) 该模块为 HTTP 客户端和服务器提供了基本的 cookie 支持.
913 Example 7-20 展示了它的使用.
914 7.8.0.1. Example 7-20. 使用 cookie 模块
915 File: cookie-example-1.py
916 import Cookie
917 import os, time
918 cookie = Cookie.SimpleCookie()
919 cookie["user"] = "Mimi"
920 cookie["timestamp"] = time.time()
921 print cookie
922 # simulate CGI roundtrip
923 os.environ["HTTP_COOKIE"] = str(cookie)
924 print
925 cookie = Cookie.SmartCookie()
926 cookie.load(os.environ["HTTP_COOKIE"])
927 for key, item in cookie.items():
928 # dictionary items are "Morsel" instances
929 # use value attribute to get actual value
930 print key, repr(item.value)
931 Set-Cookie: timestamp=736513200;
932 Set-Cookie: user=Mimi;
933 user 'Mimi'
934 timestamp '736513200'
935 7.9. robotparser 模块
936 (2.0 中新增) robotparser 模块用来读取 robots.txt 文件, 该文件用于
937 Robot Exclusion Protocol (搜索机器人排除协议?
938 http://info.webcrawler.com/mak/projects/robots/robots.html ).
939 如果你实现的一个 HTTP 机器人会访问网路上的任意站点(并不只是你自己的站
940 点), 那么最好还是用该模块检查下你所做的一切是不是受欢迎的. Example
941 7-21 展示了该模块的使用.
942 7.9.0.1. Example 7-21. 使用 robotparser 模块
943 File: robotparser-example-1.py
944 import robotparser
945 r = robotparser.RobotFileParser()
946 r.set_url("http://www.python.org/robots.txt")
947 r.read()
948 if r.can_fetch("*", "/index.html"):
949 print "may fetch the home page"
950 if r.can_fetch("*", "/tim_one/index.html"):
951 print "may fetch the tim peters archive"
952 may fetch the home page
953 7.10. ftplib 模块
954 ftplib 模块包含了一个 File Transfer Protocol (FTP , 文件传输协议)客户
955 端的实现.
956 Example 7-22 展示了如何登陆并获得登陆目录的文件列表. 注意这里的文件列
957 表 (列目录操作)格式与服务器有关(一般和主机平台的列目录工具输出格式相
958 同, 例如 Unix 下的 ls 和 Windows/DOS 下的 dir ).
959 7.10.0.1. Example 7-22. 使用 ftplib 模块获得目录列表
960 File: ftplib-example-1.py
961 import ftplib
962 ftp = ftplib.FTP("www.python.org")
963 ftp.login("anonymous", "ftplib-example-1")
964 print ftp.dir()
965 ftp.quit()
966 total 34
967 drwxrwxr-x 11 root 4127 512 Sep 14 14:18 .
968 drwxrwxr-x 11 root 4127 512 Sep 14 14:18 ..
969 drwxrwxr-x 2 root 4127 512 Sep 13 15:18 RCS
970 lrwxrwxrwx 1 root bin 11 Jun 29 14:34 README ->
971 welcome.msg
972 drwxr-xr-x 3 root wheel 512 May 19 1998 bin
973 drwxr-sr-x 3 root 1400 512 Jun 9 1997 dev
974 drwxrwxr-- 2 root 4127 512 Feb 8 1998 dup
975 drwxr-xr-x 3 root wheel 512 May 19 1998 etc
976 ...
977 下载文件很简单; 使用合适的 retr 函数即可. 注意当你下载文本文件时, 你
978 必须自己加上行结束符. Example 7-23 中使用了一个 lambda 表达式完成这项
979 工作.
980 7.10.0.2. Example 7-23. 使用 ftplib 模块下载文件
981 File: ftplib-example-2.py
982 import ftplib
983 import sys
984 def gettext(ftp, filename, outfile=None):
985 # fetch a text file
986 if outfile is None:
987 outfile = sys.stdout
988 # use a lambda to add newlines to the lines read from the server
989 ftp.retrlines("RETR " + filename, lambda s, w=outfile.write:
990 w(s+"\n"))
991 def getbinary(ftp, filename, outfile=None):
992 # fetch a binary file
993 if outfile is None:
994 outfile = sys.stdout
995 ftp.retrbinary("RETR " + filename, outfile.write)
996 ftp = ftplib.FTP("www.python.org")
997 ftp.login("anonymous", "ftplib-example-2")
998 gettext(ftp, "README")
999 getbinary(ftp, "welcome.msg")
1000 WELCOME to python.org, the Python programming language home site.
1001 You are number %N of %M allowed users. Ni!
1002 Python Web site: http://www.python.org/
1003 CONFUSED FTP CLIENT? Try begining your login password with '-' dash.
1004 This turns off continuation messages that may be confusing your client.
1005 ...
1006 最后, Example 7-24 将文件复制到 FTP 服务器上. 这个脚本使用文件扩展名来
1007 判断文件是文本文件还是二进制文件.
1008 7.10.0.3. Example 7-24. 使用 ftplib 模块上传文件
1009 File: ftplib-example-3.py
1010 import ftplib
1011 import os
1012 def upload(ftp, file):
1013 ext = os.path.splitext(file)[1]
1014 if ext in (".txt", ".htm", ".html"):
1015 ftp.storlines("STOR " + file, open(file))
1016 else:
1017 ftp.storbinary("STOR " + file, open(file, "rb"), 1024)
1018 ftp = ftplib.FTP("ftp.fbi.gov")
1019 ftp.login("mulder", "trustno1")
1020 upload(ftp, "trixie.zip")
1021 upload(ftp, "file.txt")
1022 upload(ftp, "sightings.jpg")
1023 7.11. gopherlib 模块
1024 gopherlib 模块包含了一个 gopher 客户端实现, 如 Example 7-25 所示.
1025 7.11.0.1. Example 7-25. 使用 gopherlib 模块
1026 File: gopherlib-example-1.py
1027 import gopherlib
1028 host = "gopher.spam.egg"
1029 f = gopherlib.send_selector("1/", host)
1030 for item in gopherlib.get_directory(f):
1031 print item
1032 ['0', "About Spam.Egg's Gopher Server", "0/About's Spam.Egg's
1033 Gopher Server", 'gopher.spam.egg', '70', '+']
1034 ['1', 'About Spam.Egg', '1/Spam.Egg', 'gopher.spam.egg', '70', '+']
1035 ['1', 'Misc', '1/Misc', 'gopher.spam.egg', '70', '+']
1036 ...
1037 7.12. httplib 模块
1038 httplib 模块提供了一个 HTTP 客户端接口, 如 Example 7-26 所示.
1039 7.12.0.1. Example 7-26. 使用 httplib 模块
1040 File: httplib-example-1.py
1041 import httplib
1042 USER_AGENT = "httplib-example-1.py"
1043 class Error:
1044 # indicates an HTTP error
1045 def _ _init_ _(self, url, errcode, errmsg, headers):
1046 self.url = url
1047 self.errcode = errcode
1048 self.errmsg = errmsg
1049 self.headers = headers
1050 def _ _repr_ _(self):
1051 return (
1052 "<Error for %s: %s %s>" %
1053 (self.url, self.errcode, self.errmsg)
1054 )
1055 class Server:
1056 def _ _init_ _(self, host):
1057 self.host = host
1058 def fetch(self, path):
1059 http = httplib.HTTP(self.host)
1060 # write header
1061 http.putrequest("GET", path)
1062 http.putheader("User-Agent", USER_AGENT)
1063 http.putheader("Host", self.host)
1064 http.putheader("Accept", "*/*")
1065 http.endheaders()
1066 # get response
1067 errcode, errmsg, headers = http.getreply()
1068 if errcode != 200:
1069 raise Error(errcode, errmsg, headers)
1070 file = http.getfile()
1071 return file.read()
1072 if _ _name_ _ == "_ _main_ _":
1073 server = Server("www.pythonware.com")
1074 print server.fetch("/index.htm")
1075 注意 httplib 提供的 HTTP 客户端在等待服务器回复的时候会阻塞程序. 异步
1076 的解决方法请参阅 asyncore 模块中的例子.
1077 7.12.1. 将数据发送给服务器
1078 httplib 可以用来发送其他 HTTP 命令, 例如 POST , 如 Example 7-27 所示.
1079 7.12.1.1. Example 7-27. 使用 httplib 发送数据
1080 File: httplib-example-2.py
1081 import httplib
1082 USER_AGENT = "httplib-example-2.py"
1083 def post(host, path, data, type=None):
1084 http = httplib.HTTP(host)
1085 # write header
1086 http.putrequest("PUT", path)
1087 http.putheader("User-Agent", USER_AGENT)
1088 http.putheader("Host", host)
1089 if type:
1090 http.putheader("Content-Type", type)
1091 http.putheader("Content-Length", str(len(size)))
1092 http.endheaders()
1093 # write body
1094 http.send(data)
1095 # get response
1096 errcode, errmsg, headers = http.getreply()
1097 if errcode != 200:
1098 raise Error(errcode, errmsg, headers)
1099 file = http.getfile()
1100 return file.read()
1101 if _ _name_ _ == "_ _main_ _":
1102 post("www.spam.egg", "/bacon.htm", "a piece of data", "text/plain")
1103 7.13. poplib 模块
1104 poplib 模块(如 Example 7-28 所示) 提供了一个 Post Office Protocol
1105 ( POP3 协议) 客户端实现. 这个协议用来从邮件服务器 "pop" (拷贝) 信息到
1106 你的个人电脑.
1107 7.13.0.1. Example 7-28. 使用 poplib 模块
1108 File: poplib-example-1.py
1109 import poplib
1110 import string, random
1111 import StringIO, rfc822
1112 SERVER = "pop.spam.egg"
1113 USER = "mulder"
1114 PASSWORD = "trustno1"
1115 # connect to server
1116 server = poplib.POP3(SERVER)
1117 # login
1118 server.user(USER)
1119 server.pass_(PASSWORD)
1120 # list items on server
1121 resp, items, octets = server.list()
1122 # download a random message
1123 id, size = string.split(random.choice(items))
1124 resp, text, octets = server.retr(id)
1125 text = string.join(text, "\n")
1126 file = StringIO.StringIO(text)
1127 message = rfc822.Message(file)
1128 for k, v in message.items():
1129 print k, "=", v
1130 print message.fp.read()
1131 subject = ANN: (the eff-bot guide to) The Standard Python Library
1132 message-id = <199910120808.KAA09206@spam.egg>
1133 received = (from fredrik@spam.egg)
1134 by spam.egg (8.8.7/8.8.5) id KAA09206
1135 for mulder; Tue, 12 Oct 1999 10:08:47 +0200
1136 from = Fredrik Lundh <fredrik@spam.egg>
1137 date = Tue, 12 Oct 1999 10:08:47 +0200
1138 to = mulder@spam.egg
1139 ...
1140 7.14. imaplib 模块
1141 imaplib 模块提供了一个 Internet Message Access Protocol ( IMAP, Internet
1142 消息访问协议) 的客户端实现. 这个协议允许你访问邮件服务器的邮件目录,
1143 就好像是在本机访问一样. 如 Example 7-29 所示.
1144 7.14.0.1. Example 7-29. 使用 imaplib 模块
1145 File: imaplib-example-1.py
1146 import imaplib
1147 import string, random
1148 import StringIO, rfc822
1149 SERVER = "imap.spam.egg"
1150 USER = "mulder"
1151 PASSWORD = "trustno1"
1152 # connect to server
1153 server = imaplib.IMAP4(SERVER)
1154 # login
1155 server.login(USER, PASSWORD)
1156 server.select()
1157 # list items on server
1158 resp, items = server.search(None, "ALL")
1159 items = string.split(items[0])
1160 # fetch a random item
1161 id = random.choice(items)
1162 resp, data = server.fetch(id, "(RFC822)")
1163 text = data[0][1]
1164 file = StringIO.StringIO(text)
1165 message = rfc822.Message(file)
1166 for k, v in message.items():
1167 print k, "=", v
1168 print message.fp.read()
1169 server.logout()
1170 subject = ANN: (the eff-bot guide to) The Standard Python Library
1171 message-id = <199910120816.KAA12177@larch.spam.egg>
1172 to = mulder@spam.egg
1173 date = Tue, 12 Oct 1999 10:16:19 +0200 (MET DST)
1174 from = <effbot@spam.egg>
1175 received = (effbot@spam.egg) by imap.algonet.se (8.8.8+Sun/8.6.12)
1176 id KAA12177 for effbot@spam.egg; Tue, 12 Oct 1999 10:16:19 +0200
1177 (MET DST)
1178 body text for test 5
1179 7.15. smtplib 模块
1180 smtplib 模块提供了一个 Simple Mail Transfer Protocol ( SMTP , 简单邮件
1181 传输协议) 客户端实现. 该协议用于通过 Unix 邮件服务器发送邮件, 如
1182 Example 7-30 所示.
1183 读取邮件请使用 poplib 或 imaplib 模块.
1184 7.15.0.1. Example 7-30. 使用 smtplib 模块
1185 File: smtplib-example-1.py
1186 import smtplib
1187 import string, sys
1188 HOST = "localhost"
1189 FROM = "effbot@spam.egg"
1190 TO = "fredrik@spam.egg"
1191 SUBJECT = "for your information!"
1192 BODY = "next week: how to fling an otter"
1193 body = string.join((
1194 "From: %s" % FROM,
1195 "To: %s" % TO,
1196 "Subject: %s" % SUBJECT,
1197 "",
1198 BODY), "\r\n")
1199 print body
1200 server = smtplib.SMTP(HOST)
1201 server.sendmail(FROM, [TO], body)
1202 server.quit()
1203 From: effbot@spam.egg
1204 To: fredrik@spam.egg
1205 Subject: for your information!
1206 next week: how to fling an otter
1207 7.16. telnetlib 模块
1208 telnetlib 模块提供了一个 telnet 客户端实现.
1209 Example 7-31 连接到一台 Unix 计算机, 登陆, 然后请求一个目录的列表.
1210 7.16.0.1. Example 7-31. 使用 telnetlib 模块登陆到远程服务器
1211 File: telnetlib-example-1.py
1212 import telnetlib
1213 import sys
1214 HOST = "spam.egg"
1215 USER = "mulder"
1216 PASSWORD = "trustno1"
1217 telnet = telnetlib.Telnet(HOST)
1218 telnet.read_until("login: ")
1219 telnet.write(USER + "\n")
1220 telnet.read_until("Password: ")
1221 telnet.write(PASSWORD + "\n")
1222 telnet.write("ls librarybook\n")
1223 telnet.write("exit\n")
1224 print telnet.read_all()
1225 [spam.egg mulder]$ ls
1226 README os-path-isabs-example-1.py
1227 SimpleAsyncHTTP.py os-path-isdir-example-1.py
1228 aifc-example-1.py os-path-isfile-example-1.py
1229 anydbm-example-1.py os-path-islink-example-1.py
1230 array-example-1.py os-path-ismount-example-1.py
1231 ...
1232 7.17. nntplib 模块
1233 nntplib 模块提供了一个网络新闻传输协议( Network News Transfer Protocol,
1234 NNTP )客户端的实现.
1235 7.17.1. 列出消息
1236 从新闻服务器上读取消息之前, 你必须连接这个服务器并选择一个新闻组.
1237 Example 7-32 中的脚本会从服务器下载一个完成的消息列表, 然后根据列表做
1238 简单的统计.
1239 7.17.1.1. Example 7-32. 使用 nntplib 模块列出消息
1240 File: nntplib-example-1.py
1241 import nntplib
1242 import string
1243 SERVER = "news.spam.egg"
1244 GROUP = "comp.lang.python"
1245 AUTHOR = "fredrik@pythonware.com" # eff-bots human alias
1246 # connect to server
1247 server = nntplib.NNTP(SERVER)
1248 # choose a newsgroup
1249 resp, count, first, last, name = server.group(GROUP)
1250 print "count", "=>", count
1251 print "range", "=>", first, last
1252 # list all items on the server
1253 resp, items = server.xover(first, last)
1254 # extract some statistics
1255 authors = {}
1256 subjects = {}
1257 for id, subject, author, date, message_id, references, size, lines in
1258 items:
1259 authors[author] = None
1260 if subject[:4] == "Re: ":
1261 subject = subject[4:]
1262 subjects[subject] = None
1263 if string.find(author, AUTHOR) >= 0:
1264 print id, subject
1265 print "authors", "=>", len(authors)
1266 print "subjects", "=>", len(subjects)
1267 count => 607
1268 range => 57179 57971
1269 57474 Three decades of Python!
1270 ...
1271 57477 More Python books coming...
1272 authors => 257
1273 subjects => 200
1274 7.17.2. 下载消息
1275 下载消息是很简单的, 只需要调用 article 方法, 如 Example 7-33 所示.
1276 7.17.2.1. Example 7-33. 使用 nntplib 模块下载消息
1277 File: nntplib-example-2.py
1278 import nntplib
1279 import string
1280 SERVER = "news.spam.egg"
1281 GROUP = "comp.lang.python"
1282 KEYWORD = "tkinter"
1283 # connect to server
1284 server = nntplib.NNTP(SERVER)
1285 resp, count, first, last, name = server.group(GROUP)
1286 resp, items = server.xover(first, last)
1287 for id, subject, author, date, message_id, references, size, lines in
1288 items:
1289 if string.find(string.lower(subject), KEYWORD) >= 0:
1290 resp, id, message_id, text = server.article(id)
1291 print author
1292 print subject
1293 print len(text), "lines in article"
1294 "Fredrik Lundh" <fredrik@pythonware.com>
1295 Re: Programming Tkinter (In Python)
1296 110 lines in article
1297 ...
1298 Example 7-34 展示了如何进一步处理这些消息, 你可以把它封装到一个
1299 Message 对象中(使用 rfc822 模块).
1300 7.17.2.2. Example 7-34. 使用 nntplib 和 rfc822 模块处理消息
1301 File: nntplib-example-3.py
1302 import nntplib
1303 import string, random
1304 import StringIO, rfc822
1305 SERVER = "news.spam.egg"
1306 GROUP = "comp.lang.python"
1307 # connect to server
1308 server = nntplib.NNTP(SERVER)
1309 resp, count, first, last, name = server.group(GROUP)
1310 for i in range(10):
1311 try:
1312 id = random.randint(int(first), int(last))
1313 resp, id, message_id, text = server.article(str(id))
1314 except (nntplib.error_temp, nntplib.error_perm):
1315 pass # no such message (maybe it was deleted?)
1316 else:
1317 break # found a message!
1318 else:
1319 raise SystemExit
1320 text = string.join(text, "\n")
1321 file = StringIO.StringIO(text)
1322 message = rfc822.Message(file)
1323 for k, v in message.items():
1324 print k, "=", v
1325 print message.fp.read()
1326 mime-version = 1.0
1327 content-type = text/plain; charset="iso-8859-1"
1328 message-id = <008501bf1417$1cf90b70$f29b12c2@sausage.spam.egg>
1329 lines = 22
1330 ...
1331 from = "Fredrik Lundh" <fredrik@pythonware.com>
1332 nntp-posting-host = parrot.python.org
1333 subject = ANN: (the eff-bot guide to) The Standard Python Library
1334 ...
1335 </F>
1336 到这一步后, 你可以使用 htmllib , uu , 以及 base64 继续处理这些消息.
1337 7.18. SocketServer 模块
1338 SocketServer 为各种基于 socket 的服务器提供了一个框架. 该模块提供了大
1339 量的类, 你可以用它们来创建不同的服务器.
1340 Example 7-35 使用该模块实现了一个 Internet 时间协议服务器. 你可以用前
1341 边的 timeclient 脚本连接它.
1342 7.18.0.1. Example 7-35. 使用 SocketServer 模块
1343 File: socketserver-example-1.py
1344 import SocketServer
1345 import time
1346 # user-accessible port
1347 PORT = 8037
1348 # reference time
1349 TIME1970 = 2208988800L
1350 class TimeRequestHandler(SocketServer.StreamRequestHandler):
1351 def handle(self):
1352 print "connection from", self.client_address
1353 t = int(time.time()) + TIME1970
1354 b = chr(t>>24&255) + chr(t>>16&255) + chr(t>>8&255) + chr(t&255)
1355 self.wfile.write(b)
1356 server = SocketServer.TCPServer(("", PORT), TimeRequestHandler)
1357 print "listening on port", PORT
1358 server.serve_forever()
1359 connection from ('127.0.0.1', 1488)
1360 connection from ('127.0.0.1', 1489)
1361 ...
1362 7.19. BaseHTTPServer 模块
1363 这是一个建立在 SocketServer 框架上的基本框架, 用于 HTTP 服务器.
1364 Example 7-36 在每次重新载入页面时会生成一条随机信息. path 变量包含当前
1365 URL , 你可以使用它为不同的 URL 生成不同的内容 (访问除根目录的其他任何
1366 path 该脚本都会返回一个错误页面).
1367 7.19.0.1. Example 7-36. 使用 BaseHTTPServer 模块
1368 File: basehttpserver-example-1.py
1369 import BaseHTTPServer
1370 import cgi, random, sys
1371 MESSAGES = [
1372 "That's as maybe, it's still a frog.",
1373 "Albatross! Albatross! Albatross!",
1374 "It's Wolfgang Amadeus Mozart.",
1375 "A pink form from Reading.",
1376 "Hello people, and welcome to 'It's a Tree.'"
1377 "I simply stare at the brick and it goes to sleep.",
1378 ]
1379 class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
1380 def do_GET(self):
1381 if self.path != "/":
1382 self.send_error(404, "File not found")
1383 return
1384 self.send_response(200)
1385 self.send_header("Content-type", "text/html")
1386 self.end_headers()
1387 try:
1388 # redirect stdout to client
1389 stdout = sys.stdout
1390 sys.stdout = self.wfile
1391 self.makepage()
1392 finally:
1393 sys.stdout = stdout # restore
1394 def makepage(self):
1395 # generate a random message
1396 tagline = random.choice(MESSAGES)
1397 print "<html>"
1398 print "<body>"
1399 print "<p>Today's quote: "
1400 print "<i>%s</i>" % cgi.escape(tagline)
1401 print "</body>"
1402 print "</html>"
1403 PORT = 8000
1404 httpd = BaseHTTPServer.HTTPServer(("", PORT), Handler)
1405 print "serving at port", PORT
1406 httpd.serve_forever()
1407 更有扩展性的 HTTP 框架请参阅 SimpleHTTPServer 和 CGIHTTPServer 模块.
1408 7.20. SimpleHTTPServer 模块
1409 SimpleHTTPServer 模块是一个简单的 HTTP 服务器, 它提供了标准的 GET 和
1410 HEAD 请求处理器. 客户端请求的路径名称会被翻译为一个相对文件名 (相对于
1411 服务器启动时的当前路径). Example 7-37 展示了该模块的使用.
1412 7.20.0.1. Example 7-37. 使用 SimpleHTTPServer 模块
1413 File: simplehttpserver-example-1.py
1414 import SimpleHTTPServer
1415 import SocketServer
1416 # minimal web server. serves files relative to the
1417 # current directory.
1418 PORT = 8000
1419 Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
1420 httpd = SocketServer.TCPServer(("", PORT), Handler)
1421 print "serving at port", PORT
1422 httpd.serve_forever()
1423 serving at port 8000
1424 localhost - - [11/Oct/1999 15:07:44] code 403, message Directory listing
1425 not sup
1426 ported
1427 localhost - - [11/Oct/1999 15:07:44] "GET / HTTP/1.1" 403 -
1428 localhost - - [11/Oct/1999 15:07:56] "GET /samples/sample.htm HTTP/1.1"
1429 200 -
1430 这个服务器会忽略驱动器符号和相对路径名(例如 `..`). 但它并没有任何访问
1431 验证处理, 所以请小心使用.
1432 Example 7-38 实现了个迷你的 web 代理. 发送给代理的 HTTP 请求必须包含
1433 目标服务器的完整 URI . 代理服务器使用 urllib 来获取目标服务器的数据.
1434 7.20.0.2. Example 7-38. 使用 SimpleHTTPServer 模块实现代理
1435 File: simplehttpserver-example-2.py
1436 # a truly minimal HTTP proxy
1437 import SocketServer
1438 import SimpleHTTPServer
1439 import urllib
1440 PORT = 1234
1441 class Proxy(SimpleHTTPServer.SimpleHTTPRequestHandler):
1442 def do_GET(self):
1443 self.copyfile(urllib.urlopen(self.path), self.wfile)
1444 httpd = SocketServer.ForkingTCPServer(('', PORT), Proxy)
1445 print "serving at port", PORT
1446 httpd.serve_forever()
1447 7.21. CGIHTTPServer 模块
1448 CGIHTTPServer 模块是一个可以通过公共网关接口( common gateway interface ,
1449 CGI )调用外部脚本的 HTTP 服务器. 如 Example 7-39 所示.
1450 7.21.0.1. Example 7-39. 使用 CGIHTTPServer 模块
1451 File: cgihttpserver-example-1.py
1452 import CGIHTTPServer
1453 import BaseHTTPServer
1454 class Handler(CGIHTTPServer.CGIHTTPRequestHandler):
1455 cgi_directories = ["/cgi"]
1456 PORT = 8000
1457 httpd = BaseHTTPServer.HTTPServer(("", PORT), Handler)
1458 print "serving at port", PORT
1459 httpd.serve_forever()
1460 7.22. cgi 模块
1461 cgi 模块为 CGI 脚本提供了函数和类支持. 它还可以处理 CGI 表单数据.
1462 Example 7-40 展示了一个简单的 CGI 脚本, 它返回给定目录下的文件列表
1463 (相对于脚本中指定的根目录)
1464 7.22.0.1. Example 7-40. 使用 cgi 模块
1465 File: cgi-example-1.py
1466 import cgi
1467 import os, urllib
1468 ROOT = "samples"
1469 # header
1470 print "text/html"
1471 print
1472 query = os.environ.get("QUERY_STRING")
1473 if not query:
1474 query = "."
1475 script = os.environ.get("SCRIPT_NAME", "")
1476 if not script:
1477 script = "cgi-example-1.py"
1478 print "<html>"
1479 print "<head>"
1480 print "<title>file listing</title>"
1481 print "</head>"
1482 print "</html>"
1483 print "<body>"
1484 try:
1485 files = os.listdir(os.path.join(ROOT, query))
1486 except os.error:
1487 files = []
1488 for file in files:
1489 link = cgi.escape(file)
1490 if os.path.isdir(os.path.join(ROOT, query, file)):
1491 href = script + "?" + os.path.join(query, file)
1492 print "<p><a href= '%s'>%s</a>" % (href, cgi.escape(link))
1493 else:
1494 print "<p>%s" % link
1495 print "</body>"
1496 print "</html>"
1497 text/html
1498 <html>
1499 <head>
1500 <title>file listing</title>
1501 </head>
1502 </html>
1503 <body>
1504 <p>sample.gif
1505 <p>sample.gz
1506 <p>sample.netrc
1507 ...
1508 <p>sample.txt
1509 <p>sample.xml
1510 <p>sample~
1511 <p><a href='cgi-example-1.py?web'>web</a>
1512 </body>
1513 </html>
1514 7.23. webbrowser 模块
1515 (2.0 中新增) webbrowser 模块提供了一个到系统标准 web 浏览器的接口. 它
1516 提供了一个 open 函数, 接受文件名或 URL 作为参数, 然后在浏览器中打开它.
1517 如果你又一次调用 open 函数, 那么它会尝试在相同的窗口打开新页面. 如
1518 Example 7-41 所示.
1519 7.23.0.1. Example 7-41. 使用 webbrowser 模块
1520 File: webbrowser-example-1.py
1521 import webbrowser
1522 import time
1523 webbrowser.open("http://www.pythonware.com")
1524 # wait a while, and then go to another page
1525 time.sleep(5)
1526 webbrowser.open(
1527 "http://www.pythonware.com/people/fredrik/librarybook.htm"
1528 )
1529 在 Unix 下, 该模块支持 lynx , Netscape , Mosaic , Konquerer , 和 Grail .
1530 在 Windows 和 Macintosh 下, 它会调用标准浏览器 (在注册表或是 Internet
1531 选项面板中定义).
1 8. 国际化python标准库实例-8国际化
2 o 8.1. locale 模块
3 o 8.2. unicodedata 模块
4 o 8.3. ucnhash 模块
5
6 8. 国际化
7 8.1. locale 模块
8 locale 模块提供了 C 本地化( localization )函数的接口, 如 Example 8-1
9 所示. 同时提供相关函数, 实现基于当前 locale 设置的数字, 字符串转换.
10 (而 int , float , 以及 string 模块中的相关转换函数不受 locale 设置的影
11 响.)
12 ====Example 8-1. 使用 locale 模块格式化数据=====[eg-8-1]
13 File: locale-example-1.py
14 import locale
15 print "locale", "=>", locale.setlocale(locale.LC_ALL, "")
16 # integer formatting
17 value = 4711
18 print locale.format("%d", value, 1), "==",
19 print locale.atoi(locale.format("%d", value, 1))
20 # floating point
21 value = 47.11
22 print locale.format("%f", value, 1), "==",
23 print locale.atof(locale.format("%f", value, 1))
24 info = locale.localeconv()
25 print info["int_curr_symbol"]
26 locale => Swedish_Sweden.1252
27 4,711 == 4711
28 47,110000 == 47.11
29 SEK
30 Example 8-2 展示了如何使用 locale 模块获得当前平台 locale 设置.
31 8.1.0.1. Example 8-2. 使用 locale 模块获得当前平台 locale 设置
32 File: locale-example-2.py
33 import locale
34 language, encoding = locale.getdefaultlocale()
35 print "language", language
36 print "encoding", encoding
37 language sv_SE
38 encoding cp1252
39 8.2. unicodedata 模块
40 ( 2.0 中新增) unicodedata 模块包含了 Unicode 字符的属性, 例如字符类别,
41 分解数据, 以及数值. 如 Example 8-3 所示.
42 8.2.0.1. Example 8-3. 使用 unicodedata 模块
43 File: unicodedata-example-1.py
44 import unicodedata
45 for char in [u"A", u"-", u"1", u"\N{LATIN CAPITAL LETTER O WITH
46 DIAERESIS}"]:
47 print repr(char),
48 print unicodedata.category(char),
49 print repr(unicodedata.decomposition(char)),
50 print unicodedata.decimal(char, None),
51 print unicodedata.numeric(char, None)
52 u'A' Lu '' None None
53 u'-' Pd '' None None
54 u'1' Nd '' 1 1.0
55 u'\303\226' Lu '004F 0308' None None
56 在 Python 2.0 中缺少 CJK 象形文字和韩语音节的属性. 这影响到了
57 0x3400-0x4DB5 , 0x4E00-0x9FA5 , 以及 0xAC00-D7A3 中的字符, 不过每个区
58 间内的第一个字符属性是正确的, 我们可以把字符映射到起始实现正常操作:
59 def remap(char):
60 # fix for broken unicode property database in Python 2.0
61 c = ord(char)
62 if 0x3400 <= c <= 0x4DB5:
63 return unichr(0x3400)
64 if 0x4E00 <= c <= 0x9FA5:
65 return unichr(0x4E00)
66 if 0xAC00 <= c <= 0xD7A3:
67 return unichr(0xAC00)
68 return char
69 Python 2.1 修复了这个 bug .
70 8.3. ucnhash 模块
71 (仅适用于 2.0 ) ucnhash 模块为一些 Unicode 字符代码提供了特定的命名.
72 你可以直接使用 \N{} 转义符将 Unicode 字符名称映射到字符代码上. 如
73 Example 8-4 所示.
74 8.3.0.1. Example 8-4. 使用 ucnhash 模块
75 File: ucnhash-example-1.py
76 # Python imports this module automatically, when it sees
77 # the first \N{} escape
78 # import ucnhash
79 print repr(u"\N{FROWN}")
80 print repr(u"\N{SMILE}")
81 print repr(u"\N{SKULL AND CROSSBONES}")
82 u'\u2322'
83 u'\u2323'
84 u'\u2620'
1 9. 多媒体相关模块python标准库实例-9多媒体相关模块
2 o 9.1. 概览
3 o 9.2. imghdr 模块
4 o 9.3. sndhdr 模块
5 o 9.4. whatsound 模块
6 o 9.5. aifc 模块
7 o 9.6. sunau 模块
8 o 9.7. sunaudio 模块
9 o 9.8. wave 模块
10 o 9.9. audiodev 模块
11 o 9.10. winsound 模块
12
13
14 9. 多媒体相关模块
15 "Wot? No quote?"
16 - Guido van Rossum
17 9.1. 概览
18 Python 提供了一些用于处理图片和音频文件的模块.
19 另请参阅 Pythonware Image Library ( PIL ,
20 http://www.pythonware.com/products/pil/ ), 以及 PythonWare Sound
21 Toolkit (PST , http://www.pythonware.com/products/pst/ ).
22 译注: 别参阅 PST 了, 废了, 用 pymedia 代替吧.
23 9.2. imghdr 模块
24 imghdr 模块可识别不同格式的图片文件. 当前版本可以识别 bmp , gif , jpeg ,
25 pbm , pgm , png , ppm , rast (Sun raster), rgb (SGI), tiff , 以及 xbm 图
26 像. 如 Example 9-1 所示.
27 9.2.0.1. Example 9-1. 使用 imghdr 模块
28 File: imghdr-example-1.py
29 import imghdr
30 result = imghdr.what("samples/sample.jpg")
31 if result:
32 print "file format:", result
33 else:
34 print "cannot identify file"
35 file format: jpeg
36 # 使用 PIL
37 import Image
38 im = Image.open("samples/sample.jpg")
39 print im.format, im.mode, im.size
40 9.3. sndhdr 模块
41 sndhdr 模块, 可来识别不同的音频文件格式, 并提取文件内容相关信息. 如
42 Example 9-2 所示.
43 执行成功后, what 函数将返回一个由文件类型, 采样频率, 声道数, 音轨数和
44 每个采样点位数组成的元组. 具体含义请参考 help(sndhdr) .
45 9.3.0.1. Example 9-2. 使用 sndhdr 模块
46 File: sndhdr-example-1.py
47 import sndhdr
48 result = sndhdr.what("samples/sample.wav")
49 if result:
50 print "file format:", result
51 else:
52 print "cannot identify file"
53 file format: ('wav', 44100, 1, -1, 16)
54 9.4. whatsound 模块
55 (已废弃) whatsound 是 sndhdr 模块的一个别名. 如 Example 9-3 所示.
56 9.4.0.1. Example 9-3. 使用 whatsound 模块
57 File: whatsound-example-1.py
58 import whatsound # same as sndhdr
59 result = whatsound.what("samples/sample.wav")
60 if result:
61 print "file format:", result
62 else:
63 print "cannot identify file"
64 file format: ('wav', 44100, 1, -1, 16)
65 9.5. aifc 模块
66 aifc 模块用于读写 AIFF 和 AIFC 音频文件(在 SGI 和 Macintosh 的计算机
67 上使用). 如 Example 9-4 所示.
68 9.5.0.1. Example 9-4. 使用 aifc 模块
69 File: SimpleAsyncHTTP.py
70 import asyncore
71 import string, socket
72 import StringIO
73 import mimetools, urlparse
74 class AsyncHTTP(asyncore.dispatcher_with_send):
75 # HTTP requestor
76 def _ _init_ _(self, uri, consumer):
77 asyncore.dispatcher_with_send._ _init_ _(self)
78 self.uri = uri
79 self.consumer = consumer
80 # turn the uri into a valid request
81 scheme, host, path, params, query, fragment =
82 urlparse.urlparse(uri)
83 assert scheme == "http", "only supports HTTP requests"
84 try:
85 host, port = string.split(host, ":", 1)
86 port = int(port)
87 except (TypeError, ValueError):
88 port = 80 # default port
89 if not path:
90 path = "/"
91 if params:
92 path = path + ";" + params
93 if query:
94 path = path + "?" + query
95 self.request = "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n" % (path,
96 host)
97 self.host = host
98 self.port = port
99 self.status = None
100 self.header = None
101 self.data = ""
102 # get things going!
103 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
104 self.connect((host, port))
105 def handle_connect(self):
106 # connection succeeded
107 self.send(self.request)
108 def handle_expt(self):
109 # connection failed; notify consumer (status is None)
110 self.close()
111 try:
112 http_header = self.consumer.http_header
113 except AttributeError:
114 pass
115 else:
116 http_header(self)
117 def handle_read(self):
118 data = self.recv(2048)
119 if not self.header:
120 self.data = self.data + data
121 try:
122 i = string.index(self.data, "\r\n\r\n")
123 except ValueError:
124 return # continue
125 else:
126 # parse header
127 fp = StringIO.StringIO(self.data[:i+4])
128 # status line is "HTTP/version status message"
129 status = fp.readline()
130 self.status = string.split(status, " ", 2)
131 # followed by a rfc822-style message header
132 self.header = mimetools.Message(fp)
133 # followed by a newline, and the payload (if any)
134 data = self.data[i+4:]
135 self.data = ""
136 # notify consumer (status is non-zero)
137 try:
138 http_header = self.consumer.http_header
139 except AttributeError:
140 pass
141 else:
142 http_header(self)
143 if not self.connected:
144 return # channel was closed by consumer
145 self.consumer.feed(data)
146 def handle_close(self):
147 self.consumer.close()
148 self.close()
149 9.6. sunau 模块
150 sunau 模块用于读写 Sun AU 音频文件. 如 Example 9-5 所示.
151 9.6.0.1. Example 9-5. 使用 sunau 模块
152 File: sunau-example-1.py
153 import sunau
154 w = sunau.open("samples/sample.au", "r")
155 if w.getnchannels() == 1:
156 print "mono,",
157 else:
158 print "stereo,",
159 print w.getsampwidth()*8, "bits,",
160 print w.getframerate(), "Hz sampling rate"
161 mono, 16 bits, 8012 Hz sampling rate
162 9.7. sunaudio 模块
163 sunaudio 模块用于识别 Sun AU 音频文件, 并提取其基本信息. sunau 模块为
164 Sun AU 文件提供了更完成的支持. 如 Example 9-6 所示
165 9.7.0.1. Example 9-6. 使用 sunaudio 模块
166 File: sunaudio-example-1.py
167 import sunaudio
168 file = "samples/sample.au"
169 print sunaudio.gethdr(open(file, "rb"))
170 (6761, 1, 8012, 1, 'sample.au')
171 9.8. wave 模块
172 wave 模块用于读写 Microsoft WAV 音频文件, 如 Example 9-7 所示.
173 9.8.0.1. Example 9-7. 使用 wave 模块
174 File: wave-example-1.py
175 import wave
176 w = wave.open("samples/sample.wav", "r")
177 if w.getnchannels() == 1:
178 print "mono,",
179 else:
180 print "stereo,",
181 print w.getsampwidth()*8, "bits,",
182 print w.getframerate(), "Hz sampling rate"
183 mono, 16 bits, 44100 Hz sampling rate
184 9.9. audiodev 模块
185 (只用于 Unix) audiodev 为 Sun 和 SGI 计算机提供了音频播放支持. 如
186 Example 9-8 所示.
187 9.9.0.1. Example 9-8. 使用 audiodev 模块
188 File: audiodev-example-1.py
189 import audiodev
190 import aifc
191 sound = aifc.open("samples/sample.aiff", "r")
192 player = audiodev.AudioDev()
193 player.setoutrate(sound.getframerate())
194 player.setsampwidth(sound.getsampwidth())
195 player.setnchannels(sound.getnchannels())
196 bytes_per_frame = sound.getsampwidth() * sound.getnchannels()
197 bytes_per_second = sound.getframerate() * bytes_per_frame
198 while 1:
199 data = sound.readframes(bytes_per_second)
200 if not data:
201 break
202 player.writeframes(data)
203 player.wait()
204 9.10. winsound 模块
205 (只用于 Windows ) winsound 模块允许你在 Winodws 平台上播放 Wave 文件.
206 如 Example 9-9 所示.
207 9.10.0.1. Example 9-9. 使用 winsound 模块
208 File: winsound-example-1.py
209 import winsound
210 file = "samples/sample.wav"
211 winsound.PlaySound(
212 file,
213 winsound.SND_FILENAME|winsound.SND_NOWAIT,
214 )
215 flag 变量说明:
216 • SND_FILENAME - sound 是一个 wav 文件名
217 • SND_ALIAS - sound 是一个注册表中指定的别名
218 • SND_LOOP - 重复播放直到下一次 PlaySound ; 必须指定 SND_ASYNC
219 • SND_MEMORY - sound 是一个 wav 文件的内存映像
220 • SND_PURGE - 停止指定 sound 的所有实例
221 • SND_ASYNC - 异步播放声音, 声音开始播放后函数立即返回
222 • SND_NODEFAULT - 找不到 sound 时不播放默认的 beep 声音
223 • SND_NOSTOP - 不打断当前播放中的任何 sound
224 • SND_NOWAIT - sound 驱动忙时立即返回
1 10.数据储存python标准库实例-10数据储存
2 o 10.1. 概览
3 o 10.2. anydbm 模块
4 o 10.3. whichdb 模块
5 o 10.4. shelve 模块
6 o 10.5. dbhash 模块
7 o 10.6. dbm 模块
8 o 10.7. dumbdbm 模块
9 o 10.8. gdbm 模块
10
11 10. 数据储存
12 "Unlike mainstream component programming, scripts usually do not
13 introduce new components but simply 'wire' existing ones. Scripts can be
14 seen as introducing behavior but no new state ... Of course, there is
15 nothing to stop a 'scripting' language from introducing persistent state
16 — it then simply turns into a normal programming language."
17 - Clemens Szyperski, in Component Software
18 10.1. 概览
19 Python 提供了多种相似数据库管理( database manager )的驱动, 它们的模型
20 都基于 Unix 的 dbm 库. 这些数据库和普通的字典对象类似, 但这里需要注意
21 的是它只能接受字符串作为键和值. ( shelve 模块可以处理任何类型的值)
22 10.2. anydbm 模块
23 anydbm 模块为简单数据库驱动提供了统一标准的接口.
24 当第一次被导入的时候, anydbm 模块会自动寻找一个合适的数据库驱动, 按照
25 dbhash , gdbm , dbm , 或 dumbdbm 的顺序尝试. 如果没有找到任何模块, 它
26 将引发一个 ImportError 异常.
27 open 函数用于打开或创建一个数据库(使用导入时找到的数据库驱动), 如
28 Example 10-1 所示.
29 10.2.0.1. Example 10-1. 使用 anydbm 模块
30 File: anydbm-example-1.py
31 import anydbm
32 db = anydbm.open("database", "c")
33 db["1"] = "one"
34 db["2"] = "two"
35 db["3"] = "three"
36 db.close()
37 db = anydbm.open("database", "r")
38 for key in db.keys():
39 print repr(key), repr(db[key])
40 '2' 'two'
41 '3' 'three'
42 '1' 'one'
43 10.3. whichdb 模块
44 whichdb 模块可以判断给定数据库文件的格式, 如 Example 10-2 所示.
45 10.3.0.1. Example 10-2. 使用 whichdb 模块
46 File: whichdb-example-1.py
47 import whichdb
48 filename = "database"
49 result = whichdb.whichdb(filename)
50 if result:
51 print "file created by", result
52 handler = _ _import_ _(result)
53 db = handler.open(filename, "r")
54 print db.keys()
55 else:
56 # cannot identify data base
57 if result is None:
58 print "cannot read database file", filename
59 else:
60 print "cannot identify database file", filename
61 db = None
62 这个例子中使用了 _ _import_ _ 函数来导入对应模块(还记得我们在第一章的
63 例子么?).
64 10.4. shelve 模块
65 shelve 模块使用数据库驱动实现了字典对象的持久保存. shelve 对象使用字
66 符串作为键, 但值可以是任意类型, 所有可以被 pickle 模块处理的对象都可
67 以作为它的值. 如 Example 10-3 所示.
68 10.4.0.1. Example 10-3. 使用 shelve 模块
69 File: shelve-example-1.py
70 import shelve
71 db = shelve.open("database", "c")
72 db["one"] = 1
73 db["two"] = 2
74 db["three"] = 3
75 db.close()
76 db = shelve.open("database", "r")
77 for key in db.keys():
78 print repr(key), repr(db[key])
79 'one' 1
80 'three' 3
81 'two' 2
82 Example 10-4 展示了如何使用 shelve 处理给定的数据库驱动.
83 10.4.0.2. Example 10-4. 使用 shelve 模块处理给定数据库
84 File: shelve-example-3.py
85 import shelve
86 import gdbm
87 def gdbm_shelve(filename, flag="c"):
88 return shelve.Shelf(gdbm.open(filename, flag))
89 db = gdbm_shelve("dbfile")
90 10.5. dbhash 模块
91 (可选) dbhash 模块为 bsddb 数据库驱动提供了一个 dbm 兼容的接口. 如
92 Example 10-5 所示.
93 10.5.0.1. Example 10-5. 使用 dbhash 模块
94 File: dbhash-example-1.py
95 import dbhash
96 db = dbhash.open("dbhash", "c")
97 db["one"] = "the foot"
98 db["two"] = "the shoulder"
99 db["three"] = "the other foot"
100 db["four"] = "the bridge of the nose"
101 db["five"] = "the naughty bits"
102 db["six"] = "just above the elbow"
103 db["seven"] = "two inches to the right of a very naughty bit indeed"
104 db["eight"] = "the kneecap"
105 db.close()
106 db = dbhash.open("dbhash", "r")
107 for key in db.keys():
108 print repr(key), repr(db[key])
109 10.6. dbm 模块
110 (可选) dbm 模块提供了一个到 dbm 数据库驱动的接口(在许多 Unix 平台上都
111 可用). 如 Example 10-6 所示.
112 10.6.0.1. Example 10-6. 使用 dbm 模块
113 File: dbm-example-1.py
114 import dbm
115 db = dbm.open("dbm", "c")
116 db["first"] = "bruce"
117 db["second"] = "bruce"
118 db["third"] = "bruce"
119 db["fourth"] = "bruce"
120 db["fifth"] = "michael"
121 db["fifth"] = "bruce" # overwrite
122 db.close()
123 db = dbm.open("dbm", "r")
124 for key in db.keys():
125 print repr(key), repr(db[key])
126 'first' 'bruce'
127 'second' 'bruce'
128 'fourth' 'bruce'
129 'third' 'bruce'
130 'fifth' 'bruce'
131 10.7. dumbdbm 模块
132 dumbdbm 模块是一个简单的数据库实现, 与 dbm 一类相似, 但使用纯 Python
133 实现. 它使用两个文件: 一个二进制文件 (.dat ) 用于储存数据, 一个文本文
134 件 (.dir ) 用于数据描述.
135 10.7.0.1. Example 10-7. 使用 dumbdbm 模块
136 File: dumbdbm-example-1.py
137 import dumbdbm
138 db = dumbdbm.open("dumbdbm", "c")
139 db["first"] = "fear"
140 db["second"] = "surprise"
141 db["third"] = "ruthless efficiency"
142 db["fourth"] = "an almost fanatical devotion to the Pope"
143 db["fifth"] = "nice red uniforms"
144 db.close()
145 db = dumbdbm.open("dumbdbm", "r")
146 for key in db.keys():
147 print repr(key), repr(db[key])
148 'first' 'fear'
149 'third' 'ruthless efficiency'
150 'fifth' 'nice red uniforms'
151 'second' 'surprise'
152 'fourth' 'an almost fanatical devotion to the Pope'
153 10.8. gdbm 模块
154 (可选) gdbm 模块提供了到 GNU dbm 数据驱动的接口, 如 Example 10-8 所示.
155 10.8.0.1. Example 10-8. 使用 gdbm 模块
156 File: gdbm-example-1.py
157 import gdbm
158 db = gdbm.open("gdbm", "c")
159 db["1"] = "call"
160 db["2"] = "the"
161 db["3"] = "next"
162 db["4"] = "defendant"
163 db.close()
164 db = gdbm.open("gdbm", "r")
165 keys = db.keys()
166 keys.sort()
167 for key in keys:
168 print db[key],
169 call the next defendant
1 11.工具和实用程序python标准库实例-11工具和实用程序
2 o 11.1. dis 模块
3 o 11.2. pdb 模块
4 o 11.3. bdb 模块
5 o 11.4. profile 模块
6 o 11.5. pstats 模块
7 o 11.6. tabnanny 模块
8
9 11. 工具和实用程序
10 标准库中有一些模块既可用作模块又可以作为命令行实用程序.
11 11.1. dis 模块
12 dis 模块是 Python 的反汇编器. 它可以把字节码转换为更容易让人看懂的格
13 式.
14 你可以从命令行调用反汇编器. 它会编译给定的脚本并把反汇编后的字节代码
15 输出到终端上:
16 $ dis.py hello.py
17 0 SET_LINENO 0
18 3 SET_LINENO 1
19 6 LOAD_CONST 0 ('hello again, and welcome to the
20 show')
21 9 PRINT_ITEM
22 10 PRINT_NEWLINE
23 11 LOAD_CONST 1 (None)
24 14 RETURN_VALUE
25 当然 dis 也可以作为模块使用. dis 函数接受一个类, 方法, 函数, 或者
26 code 对象作为单个参数. 如 Example 11-1 所示.
27 11.1.0.1. Example 11-1. 使用 dis 模块
28 File: dis-example-1.py
29 import dis
30 def procedure():
31 print 'hello'
32 dis.dis(procedure)
33 0 SET_LINENO 3
34 3 SET_LINENO 4
35 6 LOAD_CONST 1 ('hello')
36 9 PRINT_ITEM
37 10 PRINT_NEWLINE
38 11 LOAD_CONST 0 (None)
39 14 RETURN_VALUE
40 11.2. pdb 模块
41 pdb 模块是标准 Python 调试器( debugger ). 它基于 bdb 调试器框架.
42 你可以从命令行调用调试器 (键入 n 或 进入下一行代码, 键入 help 获得可
43 用命令列表):
44 $ pdb.py hello.py
45 > hello.py(0)?()
46 (Pdb) n
47 > hello.py()
48 (Pdb) n
49 hello again, and welcome to the show
50 --Return--
51 > hello.py(1)?()->None
52 (Pdb)
53 Example 11-2 展示了如何从程序中启动调试器.
54 11.2.0.1. Example 11-2. 使用 pdb 模块
55 File: pdb-example-1.py
56 import pdb
57 def test(n):
58 j = 0
59 for i in range(n):
60 j = j + i
61 return n
62 db = pdb.Pdb()
63 db.runcall(test, 1)
64 > pdb-example-1.py(3)test()
65 -> def test(n):
66 (Pdb) s
67 > pdb-example-1.py(4)test()
68 -> j = 0
69 (Pdb) s
70 > pdb-example-1.py(5)test()
71 -> for i in range(n):
72 ...
73 11.3. bdb 模块
74 bdb 模块为提供了一个调试器框架. 你可以使用它来创建自定义的调试器, 如
75 Example 11-3 所示.
76 你需要做的只是继承 Bdb 类, 覆盖它的 user 方法(在每次调试器停止的时候
77 被调用). 使用各种各样的 set 方法可以控制调试器.
78 11.3.0.1. Example 11-3. 使用 bdb 模块
79 File: bdb-example-1.py
80 import bdb
81 import time
82 def spam(n):
83 j = 0
84 for i in range(n):
85 j = j + i
86 return n
87 def egg(n):
88 spam(n)
89 spam(n)
90 spam(n)
91 spam(n)
92 def test(n):
93 egg(n)
94 class myDebugger(bdb.Bdb):
95 run = 0
96 def user_call(self, frame, args):
97 name = frame.f_code.co_name or "<unknown>"
98 print "call", name, args
99 self.set_continue() # continue
100 def user_line(self, frame):
101 if self.run:
102 self.run = 0
103 self.set_trace() # start tracing
104 else:
105 # arrived at breakpoint
106 name = frame.f_code.co_name or "<unknown>"
107 filename = self.canonic(frame.f_code.co_filename)
108 print "break at", filename, frame.f_lineno, "in", name
109 print "continue..."
110 self.set_continue() # continue to next breakpoint
111 def user_return(self, frame, value):
112 name = frame.f_code.co_name or "<unknown>"
113 print "return from", name, value
114 print "continue..."
115 self.set_continue() # continue
116 def user_exception(self, frame, exception):
117 name = frame.f_code.co_name or "<unknown>"
118 print "exception in", name, exception
119 print "continue..."
120 self.set_continue() # continue
121 db = myDebugger()
122 db.run = 1
123 db.set_break("bdb-example-1.py", 7)
124 db.runcall(test, 1)
125 continue...
126 call egg None
127 call spam None
128 break at C:\ematter\librarybook\bdb-example-1.py 7 in spam
129 continue...
130 call spam None
131 break at C:\ematter\librarybook\bdb-example-1.py 7 in spam
132 continue...
133 call spam None
134 break at C:\ematter\librarybook\bdb-example-1.py 7 in spam
135 continue...
136 call spam None
137 break at C:\ematter\librarybook\bdb-example-1.py 7 in spam
138 continue...
139 11.4. profile 模块
140 profile 模块是标准 Python 分析器.
141 和反汇编器, 调试器相同, 你可以从命令行调用分析器:
142 $ profile.py hello.py
143 hello again, and welcome to the show
144 3 function calls in 0.785 CPU seconds
145 Ordered by: standard name
146 ncalls tottime percall cumtime percall
147 filename:lineno(function)
148 1 0.001 0.001 0.002 0.002 <string>:1(?)
149 1 0.001 0.001 0.001 0.001 hello.py:1(?)
150 1 0.783 0.783 0.785 0.785
151 profile:0(execfile('hello.py'))
152 0 0.000 0.000 profile:0(profiler)
153 如 Example 11-4 所示, 我们还可以从程序中调用 profile 来对程序性能做分
154 析.
155 11.4.0.1. Example 11-4. U 使用 profile 模块
156 File: profile-example-1.py
157 import profile
158 def func1():
159 for i in range(1000):
160 pass
161 def func2():
162 for i in range(1000):
163 func1()
164 profile.run("func2()")
165 1003 function calls in 2.380 CPU seconds
166 Ordered by: standard name
167 ncalls tottime percall cumtime percall
168 filename:lineno(function)
169 1 0.000 0.000 2.040 2.040 <string>:1(?)
170 1000 1.950 0.002 1.950 0.002
171 profile-example-1.py:3(func1)
172 1 0.090 0.090 2.040 2.040
173 profile-example-1.py:7(func2)
174 1 0.340 0.340 2.380 2.380 profile:0(func2())
175 0 0.000 0.000 profile:0(profiler)
176 你可以使用 pstats 模块来修改结果报告的形式.
177 11.5. pstats 模块
178 pstats 模块用于分析 Python 分析器收集的数据. 如 Example 11-5 所示.
179 11.5.0.1. Example 11-5. 使用 pstats 模块
180 File: pstats-example-1.py
181 import pstats
182 import profile
183 def func1():
184 for i in range(1000):
185 pass
186 def func2():
187 for i in range(1000):
188 func1()
189 p = profile.Profile()
190 p.run("func2()")
191 s = pstats.Stats(p)
192 s.sort_stats("time", "name").print_stats()
193 1003 function calls in 1.574 CPU seconds
194 Ordered by: internal time, function name
195 ncalls tottime percall cumtime percall
196 filename:lineno(function)
197 1000 1.522 0.002 1.522 0.002
198 pstats-example-1.py:4(func1)
199 1 0.051 0.051 1.573 1.573
200 pstats-example-1.py:8(func2)
201 1 0.001 0.001 1.574 1.574 profile:0(func2())
202 1 0.000 0.000 1.573 1.573 <string>:1(?)
203 0 0.000 0.000 profile:0(profiler)
204 11.6. tabnanny 模块
205 (2.0 新增) tabnanny 模块用于检查 Python 源文件中的含糊的缩进. 当文件
206 混合了 tab 和空格两种缩进时候, nanny (保姆)会立即给出提示.
207 在下边使用的 badtabs.py 文件中, if 语句后的第一行使用 4 个空格和 1 个
208 tab . 第二行只使用了空格.
209 $ tabnanny.py -v samples/badtabs.py
210 ';samples/badtabs.py': *** Line 3: trouble in tab city! ***
211 offending line: print "world"
212 indent not equal e.g. at tab sizes 1, 2, 3, 5, 6, 7, 9
213 因为 Python 解释器把 tab 作为 8 个空格来处理, 所以这个脚本可以正常运
214 行. 在所有符合代码标准(一个 tab 为 8 个空格)的编辑器中它也会正常显示.
215 当然, 这些都骗不过 nanny .
216 Example 11-6 展示了如何在你自己的程序中使用 tabnanny .
217 11.6.0.1. Example 11-6. 使用 tabnanny 模块
218 File: tabnanny-example-1.py
219 import tabnanny
220 FILE = "samples/badtabs.py"
221 file = open(FILE)
222 for line in file.readlines():
223 print repr(line)
224 # let tabnanny look at it
225 tabnanny.check(FILE)
226 'if 1:\012'
227 ' \011print "hello"\012'
228 ' print "world"\012'
229 samples/badtabs.py 3 ' print "world"'\012'
230 将 sys.stdout 重定向到一个 StringIO 对象就可以捕获输出.
1 12.其他模块python标准库实例-12平台模块
2 o 12.1. 概览
3 o 12.2. fcntl 模块
4 o 12.3. pwd 模块
5 o 12.4. grp 模块
6 o 12.5. nis 模块
7 o 12.6. curses 模块
8 o 12.7. termios 模块
9 o 12.8. tty 模块
10 o 12.9. resource 模块
11 o 12.10. syslog 模块
12 o 12.11. msvcrt 模块
13 o 12.12. nt 模块
14 o 12.13. _winreg 模块
15 o 12.14. posix 模块
16
17 12. 其他模块
18 12.1. 概览
19 本章介绍了一些平台相关的模块. 重点放在了适用于整个平台家族的模块上.
20 (比如 Unix , Windows 家族)
21 12.2. fcntl 模块
22 (只用于 Unix) fcntl 模块为 Unix 上的 ioctl 和 fcntl 函数提供了一个接口.
23 它们用于文件句柄和 I/O 设备句柄的 "out of band" 操作, 包括读取扩展属性,
24 控制阻塞. 更改终端行为等等. (out of band management: 指使用分离的渠道
25 进行设备管理. 这使系统管理员能在机器关机的时候对服务器, 网络进行监视
26 和管理. 出处: http://en.wikipedia.org/wiki/Out-of-band_management )
27 关于如何在平台上使用这些函数, 请查阅对应的 Unix man 手册.
28 该模块同时提供了 Unix 文件锁定机制的接口. Example 12-1 展示了如何使用
29 flock 函数, 更新文件时为文件设置一个 advisory lock .
30 输出结果是由同时运行 3 个副本得到的. 像这样(都在一句命令行里):
31 python fcntl-example-1.py& python fcntl-example-1.py& python
32 fcntl-example-1.py&
33 如果你注释掉对 flock 的调用, 那么 counter 文件不会正确地更新.
34 12.2.0.1. Example 12-1. Using the fcntl Module
35 File: fcntl-example-1.py
36 import fcntl, FCNTL
37 import os, time
38 FILE = "counter.txt"
39 if not os.path.exists(FILE):
40 # create the counter file if it doesn't exist
41 # 创建 counter 文件
42 file = open(FILE, "w")
43 file.write("0")
44 file.close()
45 for i in range(20):
46 # increment the counter
47 file = open(FILE, "r+")
48 fcntl.flock(file.fileno(), FCNTL.LOCK_EX)
49 counter = int(file.readline()) + 1
50 file.seek(0)
51 file.write(str(counter))
52 file.close() # unlocks the file
53 print os.getpid(), "=>", counter
54 time.sleep(0.1)
55 30940 => 1
56 30942 => 2
57 30941 => 3
58 30940 => 4
59 30941 => 5
60 30942 => 6
61 12.3. pwd 模块
62 (只用于 Unix) pwd 提供了一个到 Unix 密码/password "数据库
63 "( /etc/passwd 以及相关文件 )的接口. 这个数据库(一般是一个纯文本文件)
64 包含本地机器用户账户的信息. 如 Example 12-2 所示.
65 12.3.0.1. Example 12-2. 使用 pwd 模块
66 File: pwd-example-1.py
67 import pwd
68 import os
69 print pwd.getpwuid(os.getgid())
70 print pwd.getpwnam("root")
71 ('effbot', 'dsWjk8', 4711, 4711, 'eff-bot', '/home/effbot', '/bin/bosh')
72 ('root', 'hs2giiw', 0, 0, 'root', '/root', '/bin/bash')
73 getpwall 函数返回一个包含所有可用用户数据库入口的列表. 你可以使用它搜
74 索一个用户.
75 当需要查询很多名称的时候, 你可以使用 getpwall 来预加载一个字典, 如
76 Example 12-3 所示.
77 12.3.0.2. Example 12-3. 使用 pwd 模块
78 File: pwd-example-2.py
79 import pwd
80 import os
81 # preload password dictionary
82 _pwd = {}
83 for info in pwd.getpwall():
84 _pwd[info[0]] = _pwd[info[2]] = info
85 def userinfo(uid):
86 # name or uid integer
87 return _pwd[uid]
88 print userinfo(os.getuid())
89 print userinfo("root")
90 ('effbot', 'dsWjk8', 4711, 4711, 'eff-bot', '/home/effbot', '/bin/bosh')
91 ('root', 'hs2giiw', 0, 0, 'root', '/root', '/bin/bash')
92 12.4. grp 模块
93 (只用于 Unix) grp 模块提供了一个到 Unix 用户组/group ( /etc/group )数
94 据库的接口. getgrgid 函数返回给定用户组 id 的相关数据(参见 Example
95 12-4 ), getgrnam 返回给定用户组名称的相关数据.
96 12.4.0.1. Example 12-4. 使用 grp 模块
97 File: grp-example-1.py
98 import grp
99 import os
100 print grp.getgrgid(os.getgid())
101 print grp.getgrnam("wheel")
102 ('effbot', '', 4711, ['effbot'])
103 ('wheel', '', 10, ['root', 'effbot', 'gorbot', 'timbot'])
104 getgrall 函数返回包含所有可用用户组数据库入口的列表.
105 如果需要执行很多用户组查询, 你可以使用 getgrall 来把当前所有的用户组
106 复制到一个字典里, 这可以节省一些时间. Example 12-5 中的 groupinfo 函数
107 返回一个用户组 id ( int )或是一个用户组名称( str )的信息.
108 12.4.0.2. Example 12-5. 使用 grp 模块缓存用户组信息
109 File: grp-example-2.py
110 import grp
111 import os
112 # preload password dictionary
113 _grp = {}
114 for info in grp.getgrall():
115 _grp[info[0]] = _grp[info[2]] = info
116 def groupinfo(gid):
117 # name or gid integer
118 return _grp[gid]
119 print groupinfo(os.getgid())
120 print groupinfo("wheel")
121 ('effbot', '', 4711, ['effbot'])
122 ('wheel', '', 10, ['root', 'effbot', 'gorbot', 'timbot'])
123 12.5. nis 模块
124 (????? Unix , ???) nis ??????? NIS ( Network Information
125 Services , ??????????? ,???) ???????, ?? Example 12-6 ???. ???????????
126 NIS ?????л?????.
127 12.5.0.1. Example 12-6. ??? nis ???
128 File: nis-example-1.py
129 import nis
130 import string
131 print nis.cat("ypservers")
132 print string.split(nis.match("bacon", "hosts.byname"))
133 {'bacon.spam.egg': 'bacon.spam.egg'}
134 ['194.18.155.250', 'bacon.spam.egg', 'bacon', 'spam-010']
135 12.6. curses 模块
136 (????? Unix ???)
137 curses ????????????????????????, ?????????????????????. ?? Example
138 12-7 ???.
139 12.6.0.1. Example 12-7. ??? curses ???
140 File: curses-example-1.py
141 import curses
142 text = [
143 "a very simple curses demo",
144 "",
145 "(press any key to exit)"
146 ]
147 # connect to the screen
148 # ???????
149 screen = curses.initscr()
150 # setup keyboard
151 # ???ü???
152 curses.noecho() # no keyboard echo
153 curses.cbreak() # don't wait for newline
154 # screen size
155 # ??????
156 rows, columns = screen.getmaxyx()
157 # draw a border around the screen
158 # ???????
159 screen.border()
160 # display centered text
161 # ???????
162 y = (rows - len(text)) / 2
163 for line in text:
164 screen.addstr(y, (columns-len(line))/2, line)
165 y = y + 1
166 screen.getch()
167 curses.endwin()
168 12.7. termios 模块
169 (只用于 Unix , 可选) termios 为 Unix 的终端控制设备提供了一个接口. 它
170 可用于控制终端通讯端口的大多方面.
171 Example 12-8 中, 该模块临时关闭了键盘回显(由第三个标志域的 ECHO 标志
172 控制).
173 12.7.0.1. Example 12-8. 使用 termios 模块
174 File: termios-example-1.py
175 import termios, TERMIOS
176 import sys
177 fileno = sys.stdin.fileno()
178 attr = termios.tcgetattr(fileno)
179 orig = attr[:]
180 print "attr =>", attr[:4] # flags
181 # disable echo flag
182 attr[3] = attr[3] & ~TERMIOS.ECHO
183 try:
184 termios.tcsetattr(fileno, TERMIOS.TCSADRAIN, attr)
185 message = raw_input("enter secret message: ")
186 print
187 finally:
188 # restore terminal settings
189 termios.tcsetattr(fileno, TERMIOS.TCSADRAIN, orig)
190 print "secret =>", repr(message)
191 attr => [1280, 5, 189, 35387]
192 enter secret message:
193 secret => 'and now for something completely different'
194 12.8. tty 模块
195 (只用于 Unix) tty 模块包含一些用于处理 tty 设备的工具函数. Example
196 12-9 将终端窗口切换为 "raw" 模式.
197 12.8.0.1. Example 12-9. 使用 tty 模块
198 File: tty-example-1.py
199 import tty
200 import os, sys
201 fileno = sys.stdin.fileno()
202 tty.setraw(fileno)
203 print raw_input("raw input: ")
204 tty.setcbreak(fileno)
205 print raw_input("cbreak input: ")
206 os.system("stty sane") # ...
207 raw input: this is raw input
208 cbreak input: this is cbreak input
209 12.9. resource 模块
210 (只用于 Unix , 可选) resource 模块用于查询或修改当前系统资源限制设置.
211 Example 12-10 展示了如何执行查询操作, Example 12-11 展示了如何执行修改
212 操作.
213 12.9.0.1. Example 12-10. 使用 resource 模块查询当前设置
214 File: resource-example-1.py
215 import resource
216 print "usage stats", "=>", resource.getrusage(resource.RUSAGE_SELF)
217 print "max cpu", "=>", resource.getrlimit(resource.RLIMIT_CPU)
218 print "max data", "=>", resource.getrlimit(resource.RLIMIT_DATA)
219 print "max processes", "=>", resource.getrlimit(resource.RLIMIT_NPROC)
220 print "page size", "=>", resource.getpagesize()
221 usage stats => (0.03, 0.02, 0, 0, 0, 0, 75, 168, 0, 0, 0, 0, 0, 0, 0,
222 0)
223 max cpu => (2147483647, 2147483647)
224 max data => (2147483647, 2147483647)
225 max processes => (256, 256)
226 page size => 4096
227 12.9.0.2. Example 12-11. 使用 resource 模块限制资源
228 File: resource-example-2.py
229 import resource
230 resource.setrlimit(resource.RLIMIT_CPU, (0, 1))
231 # pretend we're busy
232 for i in range(1000):
233 for j in range(1000):
234 for k in range(1000):
235 pass
236 CPU time limit exceeded
237 12.10. syslog 模块
238 (只用于 Unix 可选) syslog 模块用于向系统日志设备发送信息( syslogd ).
239 这些信息如何处理依不同的系统而定, 通常会被记录在一个 log 文件中, 例如
240 /var/log/messages , /var/adm/syslog , 或者其他类似处理. (如果你找不到
241 这个文件, 请联系你的系统管理员). Example 12-12 展示了该模块的使用.
242 12.10.0.1. Example 12-12. 使用 syslog 模块
243 File: syslog-example-1.py
244 import syslog
245 import sys
246 syslog.openlog(sys.argv[0])
247 syslog.syslog(syslog.LOG_NOTICE, "a log notice")
248 syslog.syslog(syslog.LOG_NOTICE, "another log notice: %s" % "watch
249 out!")
250 syslog.closelog()
251 12.11. msvcrt 模块
252 (只用于 Windows/DOS ) msvcrt 模块用于访问 Microsoft Visual C/C++
253 Runtime Library (MSVCRT) 中函数的方法.
254 Example 12-13 展示了 getch 函数, 它用于从命令行读取一次按键操作.
255 12.11.0.1. Example 12-13. 使用 msvcrt 模块获得按键值
256 File: msvcrt-example-1.py
257 import msvcrt
258 print "press 'escape' to quit..."
259 while 1:
260 char = msvcrt.getch()
261 if char == chr(27):
262 break
263 print char,
264 if char == chr(13):
265 print
266 press 'escape' to quit...
267 h e l l o
268 kbhit 函数在按键时返回(这样的捕获操作不会让 getch 阻塞), 如 Example
269 12-14 所示.
270 12.11.0.2. Example 12-14. 使用 msvcrt 模块接受键盘输入
271 File: msvcrt-example-2.py
272 import msvcrt
273 import time
274 print "press SPACE to enter the serial number"
275 while not msvcrt.kbhit() or msvcrt.getch() != " ":
276 # do something else
277 print ".",
278 time.sleep(0.1)
279 print
280 # clear the keyboard buffer
281 # 清除键盘缓冲区
282 while msvcrt.kbhit():
283 msvcrt.getch()
284 serial = raw_input("enter your serial number: ")
285 print "serial number is", serial
286 press SPACE to enter the serial number
287 . . . . . . . . . . . . . . . . . . . . . . . .
288 enter your serial number: 10
289 serial number is 10
290 译注: 某翻译在这里评注道: 我能在 cmd 下运行. 用别的 IDLE 要不然卡住,
291 要不然接受不了键盘输入. 原因未知. 这是因为 IDLE 启动两个 python 线程,
292 使用 socket 发送数据, 获得程序返回的.
293 locking 函数实现了 Windows 下的跨进程文件锁定, 如 Example 12-15 所示.
294 12.11.0.3. Example 12-15. 使用 msvcrt 模块锁定文件
295 File: msvcrt-example-3.py
296 import msvcrt
297 import os
298 LK_UNLCK = 0 # unlock the file region 解锁区域
299 LK_LOCK = 1 # lock the file region 锁定文件区域
300 LK_NBLCK = 2 # non-blocking lock 非阻塞文件锁
301 LK_RLCK = 3 # lock for writing 为写入文件提供锁定
302 LK_NBRLCK = 4 # non-blocking lock for writing 为写入文件提供的非阻塞锁
303 定
304 FILE = "counter.txt"
305 if not os.path.exists(FILE):
306 file = open(FILE, "w")
307 file.write("0")
308 file.close()
309 for i in range(20):
310 file = open(FILE, "r+")
311 # look from current position (0) to end of file
312 msvcrt.locking(file.fileno(), LK_LOCK, os.path.getsize(FILE))
313 counter = int(file.readline()) + 1
314 file.seek(0)
315 file.write(str(counter))
316 file.close() # unlocks the file
317 print os.getpid(), "=>", counter
318 time.sleep(0.1)
319 208 => 21
320 208 => 22
321 208 => 23
322 208 => 24
323 208 => 25
324 208 => 26
325 12.12. nt 模块
326 (非直接使用模块, 只用于 Windows ) nt 模块是 os 模块在 Windows 平台下调
327 用的执行模块. 几乎没有任何原因直接使用这个模块, 请使用 os 模块替代.
328 Example 12-16 展示了它的使用.
329 12.12.0.1. Example 12-16. 使用 nt 模块
330 File: nt-example-1.py
331 import nt
332 # in real life, use os.listdir and os.stat instead!
333 for file in nt.listdir("."):
334 print file, nt.stat(file)[6]
335 aifc-example-1.py 314
336 anydbm-example-1.py 259
337 array-example-1.py 48
338 12.13. _winreg 模块
339 (只用于 Windows , 2.0 中新增) _winreg 模块提供了访问 Windows 注册表数
340 据库的一个基本接口. Example 12-17 展示了它的使用.
341 12.13.0.1. Example 12-17. 使用 _winreg 模块
342 File: winreg-example-1.py
343 import _winreg
344 explorer = _winreg.OpenKey(
345 _winreg.HKEY_CURRENT_USER,
346 "Software\\Microsoft\\Windows\CurrentVersion\\Explorer"
347 )
348 # list values owned by this registry key
349 # 列出该注册表键下的所有值
350 try:
351 i = 0
352 while 1:
353 name, value, type= _winreg.EnumValue(explorer, i)
354 print repr(name),
355 i += 1
356 except WindowsError:
357 print
358 value, type = _winreg.QueryValueEx(explorer, "Logon User Name")
359 print
360 print "user is", repr(value)
361 'Logon User Name' 'CleanShutdown' 'ShellState' 'Shutdown Setting'
362 'Reason Setting' 'FaultCount' 'FaultTime' 'IconUnderline'...
363 user is u'Effbot'
364 12.14. posix 模块
365 (非直接使用模块, 只用于 Unix/POSIX ) posix 模块是 os 模块在 Unix 及其
366 他 POSIX 系统下使用的实现模块. 一般只需要通过 os 模块访问它即可. 如
367 Example 12-18 所示.
368 12.14.0.1. Example 12-18. 使用 posix 模块
369 File: posix-example-1.py
370 import posix
371 for file in posix.listdir("."):
372 print file, posix.stat(file)[6]
373 aifc-example-1.py 314
374 anydbm-example-1.py 259
375 array-example-1.py 48
1 13.执行支持模块python标准库实例-13执行支持模块
2 o 13.1. dospath 模块
3 o 13.2. macpath 模块
4 o 13.3. ntpath 模块
5 o 13.4. posixpath 模块
6 o 13.5. strop 模块
7 o 13.6. imp 模块
8 o 13.7. new 模块
9 o 13.8. pre 模块
10 o 13.9. sre 模块
11 o 13.10. py_compile 模块
12 o 13.11. compileall 模块
13 o 13.12. ihooks 模块
14 o 13.13. linecache 模块
15 o 13.14. macurl2path 模块
16 o 13.15. nturl2path 模块
17 o 13.16. tokenize 模块
18 o 13.17. keyword 模块
19 o 13.18. parser 模块
20 o 13.19. symbol 模块
21 o 13.20. token 模块
22
23
24 13. 执行支持模块
25 就是其他模块中用到的模块.
26 13.1. dospath 模块
27 dospath 模块(参见 Example 13-1 )提供了 DOS 平台下的 os.path 功能. 你可
28 以使用它在其他平台处理 DOS 路径.
29 13.1.0.1. Example 13-1. 使用 dospath 模块
30 File: dospath-example-1.py
31 import dospath
32 file = "/my/little/pony"
33 print "isabs", "=>", dospath.isabs(file)
34 print "dirname", "=>", dospath.dirname(file)
35 print "basename", "=>", dospath.basename(file)
36 print "normpath", "=>", dospath.normpath(file)
37 print "split", "=>", dospath.split(file)
38 print "join", "=>", dospath.join(file, "zorba")
39 isabs => 1
40 dirname => /my/little
41 basename => pony
42 normpath => \my\little\pony
43 split => ('/my/little', 'pony')
44 join => /my/little/pony\zorba
45 注意 Python 的 DOS 支持可以使用斜杠和反斜杠作为目录分隔符.
46 13.2. macpath 模块
47 macpath 模块( 参见 Example 13-2 )提供了 Macintosh 平台下的 os.path 功
48 能. 你也可以使用它在其他平台处理 Macintosh 路径.
49 13.2.0.1. Example 13-2. 使用 macpath 模块
50 File: macpath-example-1.py
51 import macpath
52 file = "my:little:pony"
53 print "isabs", "=>", macpath.isabs(file)
54 print "dirname", "=>", macpath.dirname(file)
55 print "basename", "=>", macpath.basename(file)
56 print "normpath", "=>", macpath.normpath(file)
57 print "split", "=>", macpath.split(file)
58 print "join", "=>", macpath.join(file, "zorba")
59 isabs => 1
60 dirname => my:little
61 basename => pony
62 normpath => my:little:pony
63 split => ('my:little', 'pony')
64 join => my:little:pony:zorba
65 13.3. ntpath 模块
66 ntpath 模块( 参见 Example 13-3 )提供了 Windows 平台下的 os.path 功能.
67 你也可以使用它在其他平台处理 Windows 路径.
68 13.3.0.1. Example 13-3. 使用 ntpath 模块
69 File: ntpath-example-1.py
70 import ntpath
71 file = "/my/little/pony"
72 print "isabs", "=>", ntpath.isabs(file)
73 print "dirname", "=>", ntpath.dirname(file)
74 print "basename", "=>", ntpath.basename(file)
75 print "normpath", "=>", ntpath.normpath(file)
76 print "split", "=>", ntpath.split(file)
77 print "join", "=>", ntpath.join(file, "zorba")
78 isabs => 1
79 dirname => /my/little
80 basename => pony
81 normpath => \my\little\pony
82 split => ('/my/little', 'pony')
83 join => /my/little/pony\zorba
84 注意该模块可以同时使用斜杠和反斜杠作为目录分隔符.
85 13.4. posixpath 模块
86 posixpath 模块( 参见 Example 13-4 )提供了 Unix 和其他 POSIX 兼容平台下
87 的 os.path 功能. 你也可以使用它在其他平台处理 POSIX 路径. 另外, 它也
88 可以处理 URL .
89 13.4.0.1. Example 13-4. 使用 posixpath 模块
90 File: posixpath-example-1.py
91 import posixpath
92 file = "/my/little/pony"
93 print "isabs", "=>", posixpath.isabs(file)
94 print "dirname", "=>", posixpath.dirname(file)
95 print "basename", "=>", posixpath.basename(file)
96 print "normpath", "=>", posixpath.normpath(file)
97 print "split", "=>", posixpath.split(file)
98 print "join", "=>", posixpath.join(file, "zorba")
99 isabs => 1
100 dirname => /my/little
101 basename => pony
102 normpath => /my/little/pony
103 split => ('/my/little', 'pony')
104 join => /my/little/pony/zorba
105 13.5. strop 模块
106 (已废弃) strop 为 string 模块中的大多函数提供了底层 C 语言实现. string
107 模块会自动调用它, 所以一般你不需要直接使用它.
108 不过在导入 Python 模块之前处理路径的时候你可能会用到它. 如 Example
109 13-5 所示.
110 13.5.0.1. Example 13-5. 使用 strop 模块
111 File: strop-example-1.py
112 import strop
113 import sys
114 # assuming we have an executable named ".../executable", add a
115 # directory named ".../executable-extra" to the path
116 if strop.lower(sys.executable)[-4:] == ".exe":
117 extra = sys.executable[:-4] # windows
118 else:
119 extra = sys.executable
120 sys.path.insert(0, extra + "-extra")
121 import mymodule
122 在 Python 2.0 及以后版本中, 你应该使用字符串方法代替 strop , 例如在上
123 边的代码中. 使用 "sys.executable.lower() " 替换
124 "strop.lower(sys.executable) " .
125 13.6. imp 模块
126 imp 模块包含的函数可以用于实现自定义的 import 行为. Example 13-6 重载
127 了 import 语句, 实现了对模块来源的记录功能.
128 13.6.0.1. Example 13-6. 使用 imp 模块
129 File: imp-example-1.py
130 import imp
131 import sys
132 def my_import(name, globals=None, locals=None, fromlist=None):
133 try:
134 module = sys.modules[name] # already imported?
135 except KeyError:
136 file, pathname, description = imp.find_module(name)
137 print "import", name, "from", pathname, description
138 module = imp.load_module(name, file, pathname, description)
139 return module
140 import _ _builtin_ _
141 _ _builtin_ _._ _import_ _ = my_import
142 import xmllib
143 import xmllib from /python/lib/xmllib.py ('.py', 'r', 1)
144 import re from /python/lib/re.py ('.py', 'r', 1)
145 import sre from /python/lib/sre.py ('.py', 'r', 1)
146 import sre_compile from /python/lib/sre_compile.py ('.py', 'r', 1)
147 import _sre from /python/_sre.pyd ('.pyd', 'rb', 3)
148 注意这里的导入功能不支持包. 具体实现请参阅 knee 模块的源代码.
149 13.7. new 模块
150 new 模块是一个底层的模块, 你可以使用它来创建不同的内建对象, 例如类对
151 象, 函数对象, 以及其他由 Python 运行时系统创建的类型. Example 13-7 展
152 示了该模块的使用.
153 如果你使用的是 1.5.2 版本 , 那么你有可能需要重新编译 Python 来使用这
154 个模块, 在默认情况下并不是所有平台都有这个模块. 在 2.0 及以后版本中,
155 不需要这么做.
156 13.7.0.1. Example 13-7. 使用 new 模块
157 File: new-example-1.py
158 import new
159 class Sample:
160 a = "default"
161 def _ _init_ _(self):
162 self.a = "initialised"
163 def _ _repr_ _(self):
164 return self.a
165 #
166 # create instances
167 a = Sample()
168 print "normal", "=>", a
169 b = new.instance(Sample, {})
170 print "new.instance", "=>", b
171 b._ _init_ _()
172 print "after _ _init_ _", "=>", b
173 c = new.instance(Sample, {"a": "assigned"})
174 print "new.instance w. dictionary", "=>", c
175 normal => initialised
176 new.instance => default
177 after _ _init_ _ => initialised
178 new.instance w. dictionary => assigned
179 13.8. pre 模块
180 (已废弃) pre 模块是 1.5.2 中 re 模块调用的实现功能模块. 在当前版本中
181 已废弃. Example 13-8 展示了它的使用.
182 13.8.0.1. Example 13-8. 使用 pre 模块
183 File: pre-example-1.py
184 import pre
185 p = pre.compile("[Python]+")
186 print p.findall("Python is not that bad")
187 ['Python', 'not', 'th', 't']
188 13.9. sre 模块
189 (功能实现模块, 已声明不支持) sre 模块是 re 模块的底层实现. 一般没必要
190 直接使用它, 而且以后版本将不会支持它. Example 13-9 展示了它的使用.
191 13.9.0.1. Example 13-9. 使用 sre 模块
192 File: sre-example-1.py
193 import sre
194 text = "The Bookshop Sketch"
195 # a single character
196 m = sre.match(".", text)
197 if m: print repr("."), "=>", repr(m.group(0))
198 # and so on, for all 're' examples...
199 '.' => 'T'
200 13.10. py_compile 模块
201 py_compile 模块用于将 Python 模块编译为字节代码. 它和 Python 的
202 import 语句行为类似, 不过它接受文件名而不是模块名作为参数. 使用方法如
203 Example 13-10 所示.
204 13.10.0.1. Example 13-10. 使用 py_compile 模块
205 File: py-compile-example-1.py
206 import py_compile
207 # explicitly compile this module
208 py_compile.compile("py-compile-example-1.py")
209 compileall 模块可以把一个目录树下的所有 Python 文件编译为字节代码.
210 13.11. compileall 模块
211 compileall 模块用于将给定目录下(以及 Python path )的所有 Python 脚本编
212 译为字节代码. 它也可以作为可执行脚本使用(在 Unix 系统下, Python 安装
213 时会自动调用执行它). 用法参见 Example 13-11 .
214 13.11.0.1. Example 13-11. 使用 compileall 模块编译目录中的所有脚本
215 File: compileall-example-1.py
216 import compileall
217 print "This may take a while!"
218 compileall.compile_dir(".", force=1)
219 This may take a while!
220 Listing . ...
221 Compiling .\SimpleAsyncHTTP.py ...
222 Compiling .\aifc-example-1.py ...
223 Compiling .\anydbm-example-1.py ...
224 ...
225 13.12. ihooks 模块
226 ihooks 模块为替换导入提供了一个框架. 这允许多个导入机制共存. 使用方法
227 参见 Example 13-12 .
228 13.12.0.1. Example 13-12. 使用 ihooks 模块
229 File: ihooks-example-1.py
230 import ihooks, imp, os
231 def import_from(filename):
232 "Import module from a named file"
233 loader = ihooks.BasicModuleLoader()
234 path, file = os.path.split(filename)
235 name, ext = os.path.splitext(file)
236 m = loader.find_module_in_dir(name, path)
237 if not m:
238 raise ImportError, name
239 m = loader.load_module(name, m)
240 return m
241 colorsys = import_from("/python/lib/colorsys.py")
242 print colorsys
243 <module 'colorsys' from '/python/lib/colorsys.py'>
244 13.13. linecache 模块
245 linecache 模块用于从模块源文件中读取代码. 它会缓存最近访问的模块 (整
246 个源文件). 如 Example 13-13 .
247 13.13.0.1. Example 13-13. 使用 linecache 模块
248 File: linecache-example-1.py
249 import linecache
250 print linecache.getline("linecache-example-1.py", 5)
251 print linecache.getline("linecache-example-1.py", 5)
252 traceback 模块使用这个模块实现了对导入操作的跟踪.
253 13.14. macurl2path 模块
254 (功能实现模块) macurl2path 模块用于 URL 和 Macintosh 文件名的相互映射.
255 一般没有必要直接使用它, 请使用 urllib 中的机制. 它的用法参见 Example
256 13-14 .
257 13.14.0.1. Example 13-14. 使用 macurl2path 模块
258 File: macurl2path-example-1.py
259 import macurl2path
260 file = ":my:little:pony"
261 print macurl2path.pathname2url(file)
262 print macurl2path.url2pathname(macurl2path.pathname2url(file))
263 my/little/pony
264 :my:little:pony
265 13.15. nturl2path 模块
266 (功能实现模块) nturl2path 模块用于 URL 和 Windows 文件名的相互映射.
267 用法参见 Example 13-15 .
268 13.15.0.1. Example 13-15. 使用 nturl2path 模块
269 File: nturl2path-example-1.py
270 import nturl2path
271 file = r"c:\my\little\pony"
272 print nturl2path.pathname2url(file)
273 print nturl2path.url2pathname(nturl2path.pathname2url(file))
274 ///C|/my/little/pony
275 C:\my\little\pony
276 同样地, 请通过 urllib 模块来访问这些函数, 如 Example 13-16 所示.
277 13.15.0.2. Example 13-16. 通过 urllib 调用 nturl2path 模块
278 File: nturl2path-example-2.py
279 import urllib
280 file = r"c:\my\little\pony"
281 print urllib.pathname2url(file)
282 print urllib.url2pathname(urllib.pathname2url(file))
283 ///C|/my/little/pony
284 C:\my\little\pony
285 13.16. tokenize 模块
286 tokenize 模块将一段 Python 源文件分割成不同的 token . 你可以在代码高
287 亮工具中使用它.
288 在 Example 13-17 中, 我们分别打印出这些 token .
289 13.16.0.1. Example 13-17. 使用 tokenize 模块
290 File: tokenize-example-1.py
291 import tokenize
292 file = open("tokenize-example-1.py")
293 def handle_token(type, token, (srow, scol), (erow, ecol), line):
294 print "%d,%d-%d,%d:\t%s\t%s" % \
295 (srow, scol, erow, ecol, tokenize.tok_name[type], repr(token))
296 tokenize.tokenize(
297 file.readline,
298 handle_token
299 )
300 1,0-1,6: NAME 'import'
301 1,7-1,15: NAME 'tokenize'
302 1,15-1,16: NEWLINE '\012'
303 2,0-2,1: NL '\012'
304 3,0-3,4: NAME 'file'
305 3,5-3,6: OP '='
306 3,7-3,11: NAME 'open'
307 3,11-3,12: OP '('
308 3,12-3,35: STRING '"tokenize-example-1.py"'
309 3,35-3,36: OP ')'
310 3,36-3,37: NEWLINE '\012'
311 ...
312 注意这里的 tokenize 函数接受两个可调用对象作为参数: 前一个用于获取新
313 的代码行, 第二个用于在获得每个 token 时调用.
314 13.17. keyword 模块
315 keyword 模块(参见 Example 13-18 )有一个包含当前 Python 版本所使用的关
316 键字的列表. 它还提供了一个字典, 以关键字作为 key , 以一个描述性函数作
317 为 value , 它可用于检查给定单词是否是 Python 关键字.
318 13.17.0.1. Example 13-18. 使用 keyword 模块
319 File: keyword-example-1.py
320 import keyword
321 name = raw_input("Enter module name: ")
322 if keyword.iskeyword(name):
323 print name, "is a reserved word."
324 print "here's a complete list of reserved words:"
325 print keyword.kwlist
326 Enter module name: assert
327 assert is a reserved word.
328 here's a complete list of reserved words:
329 ['and', 'assert', 'break', 'class', 'continue', 'def', 'del',
330 'elif', 'else', 'except', 'exec', 'finally', 'for', 'from',
331 'global', 'if', 'import', 'in', 'is', 'lambda', 'not', 'or',
332 'pass', 'print', 'raise', 'return', 'try', 'while']
333 13.18. parser 模块
334 (可选) parser 模块提供了一个到 Python 内建语法分析器和编译器的接口.
335 Example 13-19 将一个简单的表达式编译为一个抽象语法树( abstract syntax
336 tree , AST ), 然后将 AST 转换为一个嵌套列表, 转储树 ( 其中每个节点包含
337 一个语法符号或者是一个 token )中的内容, 将所有数字加上 1 , 最后将列表
338 转回一个代码对象. 至少我认为它是这么做的.
339 13.18.0.1. Example 13-19. 使用 parser 模块
340 File: parser-example-1.py
341 import parser
342 import symbol, token
343 def dump_and_modify(node):
344 name = symbol.sym_name.get(node[0])
345 if name is None:
346 name = token.tok_name.get(node[0])
347 print name,
348 for i in range(1, len(node)):
349 item = node[i]
350 if type(item) is type([]):
351 dump_and_modify(item)
352 else:
353 print repr(item)
354 if name == "NUMBER":
355 # increment all numbers!
356 node[i] = repr(int(item)+1)
357 ast = parser.expr("1 + 3")
358 list = ast.tolist()
359 dump_and_modify(list)
360 ast = parser.sequence2ast(list)
361 print eval(parser.compileast(ast))
362 eval_input testlist test and_test not_test comparison
363 expr xor_expr and_expr shift_expr arith_expr term factor
364 power atom NUMBER '1'
365 PLUS '+'
366 term factor power atom NUMBER '3'
367 NEWLINE ''
368 ENDMARKER ''
369 6
370 13.19. symbol 模块
371 symbol 模块包含 Python 语法中的非终止符号. 可能只有你涉及 parser 模块
372 的时候用到它. 用法参见 Example 13-20 .
373 13.19.0.1. Example 13-20. 使用 symbol 模块
374 File: symbol-example-1.py
375 import symbol
376 print "print", symbol.print_stmt
377 print "return", symbol.return_stmt
378 print 268
379 return 274
380 13.20. token 模块
381 token 模块包含标准 Python tokenizer 所使用的 token 标记. 如 Example
382 13-21 所示.
383 13.20.0.1. Example 13-21. 使用 token 模块
384 File: token-example-1.py
385 import token
386 print "NUMBER", token.NUMBER
387 print "PLUS", token.STAR
388 print "STRING", token.STRING
389 NUMBER 2
390 PLUS 16
391 STRING 3
1 14.其他模块python标准库实例-14其他模块
2 o 14.1. 概览
3 o 14.2. pyclbr 模块
4 o 14.3. filecmp 模块
5 o 14.4. cmd 模块
6 o 14.5. rexec 模块
7 o 14.6. Bastion 模块
8 o 14.7. readline 模块
9 o 14.8. rlcompleter 模块
10 o 14.9. statvfs 模块
11 o 14.10. calendar 模块
12 o 14.11. sched 模块
13 o 14.12. statcache 模块
14 o 14.13. grep 模块
15 o 14.14. dircache 模块
16 o 14.15. dircmp 模块
17 o 14.16. cmp 模块
18 o 14.17. cmpcache 模块
19 o 14.18. util 模块
20 o 14.19. soundex 模块
21 o 14.20. timing 模块
22 o 14.21. posixfile 模块
23 o 14.22. bisect 模块
24 o 14.23. knee 模块
25 o 14.24. tzparse 模块
26 o 14.25. regex 模块
27 o 14.26. regsub 模块
28 o 14.27. reconvert 模块
29 o 14.28. regex_syntax 模块
30 o 14.29. find 模块
31
32
33 14. 其他模块
34 14.1. 概览
35 本章描述的是一些并不怎么常见的模块. 一些是很实用的, 另些是已经废弃的
36 模块.
37 14.2. pyclbr 模块
38 pyclbr 模块包含一个基本的 Python 类解析器, 如 Example 14-1 所示.
39 版本 1.5.2 中, 改模块只包含一个 readmodule 函数, 解析给定模块, 返回一
40 个模块所有顶层类组成的列表.
41 14.2.0.1. Example 14-1. 使用 pyclbr 模块
42 File: pyclbr-example-1.py
43 import pyclbr
44 mod = pyclbr.readmodule("cgi")
45 for k, v in mod.items():
46 print k, v
47 MiniFieldStorage <pyclbr.Class instance at 7873b0>
48 InterpFormContentDict <pyclbr.Class instance at 79bd00>
49 FieldStorage <pyclbr.Class instance at 790e20>
50 SvFormContentDict <pyclbr.Class instance at 79b5e0>
51 StringIO <pyclbr.Class instance at 77dd90>
52 FormContent <pyclbr.Class instance at 79bd60>
53 FormContentDict <pyclbr.Class instance at 79a9c0>
54 2.0 及以后版本中, 添加了另个接口 readmodule_ex , 它还会读取全局函数.
55 如 Example 14-2 所示.
56 14.2.0.2. Example 14-2. 使用 pyclbr 模块读取类和函数
57 File: pyclbr-example-3.py
58 import pyclbr
59 # 2.0 and later
60 mod = pyclbr.readmodule_ex("cgi")
61 for k, v in mod.items():
62 print k, v
63 MiniFieldStorage <pyclbr.Class instance at 00905D2C>
64 parse_header <pyclbr.Function instance at 00905BD4>
65 test <pyclbr.Function instance at 00906FBC>
66 print_environ_usage <pyclbr.Function instance at 00907C94>
67 parse_multipart <pyclbr.Function instance at 00905294>
68 FormContentDict <pyclbr.Class instance at 008D3494>
69 initlog <pyclbr.Function instance at 00904AAC>
70 parse <pyclbr.Function instance at 00904EFC>
71 StringIO <pyclbr.Class instance at 00903EAC>
72 SvFormContentDict <pyclbr.Class instance at 00906824>
73 ...
74 访问类实例的属性可以获得关于类的更多信息, 如 Example 14-3 所示.
75 14.2.0.3. Example 14-3. 使用 pyclbr 模块
76 File: pyclbr-example-2.py
77 import pyclbr
78 import string
79 mod = pyclbr.readmodule("cgi")
80 def dump(c):
81 # print class header
82 s = "class " + c.name
83 if c.super:
84 s = s + "(" + string.join(map(lambda v: v.name, c.super), ", ")
85 + ")"
86 print s + ":"
87 # print method names, sorted by line number
88 methods = c.methods.items()
89 methods.sort(lambda a, b: cmp(a[1], b[1]))
90 for method, lineno in methods:
91 print " def " + method
92 print
93 for k, v in mod.items():
94 dump(v)
95 class MiniFieldStorage:
96 def _ _init_ _
97 def _ _repr_ _
98 class InterpFormContentDict(SvFormContentDict):
99 def _ _getitem_ _
100 def values
101 def items
102 ...
103 14.3. filecmp 模块
104 ( 2.0 新增) filecmp 模块用于比较文件和目录, 如 Example 14-4 所示.
105 14.3.0.1. Example 14-4. 使用 filecmp 模块
106 File: filecmp-example-1.py
107 import filecmp
108 if filecmp.cmp("samples/sample.au", "samples/sample.wav"):
109 print "files are identical"
110 else:
111 print "files differ!"
112 # files differ!
113 1.5.2 以及先前版本中, 你可以使用 cmp 和 dircmp 模块代替.
114 14.4. cmd 模块
115 cmd 模块为命令行接口( command-line interfaces , CLI )提供了一个简单的
116 框架. 它被用在 pdb 模块中, 当然你也可以在自己的程序中使用它, 如
117 Example 14-5 所示.
118 你只需要继承 Cmd 类, 定义 do 和 help 方法. 基类会自动地将这些方法转换
119 为对应命令.
120 14.4.0.1. Example 14-5. 使用 cmd 模块
121 File: cmd-example-1.py
122 import cmd
123 import string, sys
124 class CLI(cmd.Cmd):
125 def _ _init_ _(self):
126 cmd.Cmd._ _init_ _(self)
127 self.prompt = '> '
128 def do_hello(self, arg):
129 print "hello again", arg, "!"
130 def help_hello(self):
131 print "syntax: hello [message]",
132 print "-- prints a hello message"
133 def do_quit(self, arg):
134 sys.exit(1)
135 def help_quit(self):
136 print "syntax: quit",
137 print "-- terminates the application"
138 # shortcuts
139 do_q = do_quit
140 #
141 # try it out
142 cli = CLI()
143 cli.cmdloop()
144 > help
145 Documented commands (type help <topic>):
146 ========================================
147 hello quit
148 Undocumented commands:
149 ======================
150 help q
151 > hello world
152 hello again world !
153 > q
154 14.5. rexec 模块
155 Feather 注: 版本 2.3 时取消了改模块的支持, 具体原因请参阅 :
156 http://www.amk.ca/python/howto/rexec/ 和
157 http://mail.python.org/pipermail/python-dev/2002-December/031160.html
158 解决方法请参阅:
159 http://mail.python.org/pipermail/python-list/2003-November/234581.htm
160 l
161 rexec 模块提供了在限制环境下的 exec , eval , 以及 import 语句, 如
162 Example 14-6 所示. 在这个环境下, 所有可能对机器造成威胁的函数都不可
163 用.
164 14.5.0.1. Example 14-6. 使用 rexec 模块
165 File: rexec-example-1.py
166 import rexec
167 r = rexec.RExec()
168 print r.r_eval("1+2+3")
169 print r.r_eval("_ _import_ _('os').remove('file')")
170 6
171 Traceback (innermost last):
172 File "rexec-example-1.py", line 5, in ?
173 print r.r_eval("_ _import_ _('os').remove('file')")
174 File "/usr/local/lib/python1.5/rexec.py", line 257, in r_eval
175 return eval(code, m._ _dict_ _)
176 File "<string>", line 0, in ?
177 AttributeError: remove
178 14.6. Bastion 模块
179 Feather 注: 版本 2.3 时取消了改模块的支持, 具体原因请参阅 :
180 http://www.amk.ca/python/howto/rexec/ 和
181 http://mail.python.org/pipermail/python-dev/2003-January/031848.html
182 Bastion 模块, 允许你控制给定对象如何使用, 如 Example 14-7 所示. 你可
183 以通过它把对象从未限制部分传递到限制部分.
184 默认情况下, 所有的实例变量都是隐藏的, 所有的方法以下划线开头.
185 14.6.0.1. Example 14-7. 使用 Bastion 模块
186 File: bastion-example-1.py
187 import Bastion
188 class Sample:
189 value = 0
190 def _set(self, value):
191 self.value = value
192 def setvalue(self, value):
193 if 10 < value <= 20:
194 self._set(value)
195 else:
196 raise ValueError, "illegal value"
197 def getvalue(self):
198 return self.value
199 #
200 # try it
201 s = Sample()
202 s._set(100) # cheat
203 print s.getvalue()
204 s = Bastion.Bastion(Sample())
205 s._set(100) # attempt to cheat
206 print s.getvalue()
207 100
208 Traceback (innermost last):
209 ...
210 AttributeError: _set
211 你可以控制发布哪个函数. 在 Example 14- 中, 内部方法可以从外部调用, 但
212 getvalue 不再起作用.
213 14.6.0.2. Example 14-8. 使用 Bastion 模块处理非标准过滤器
214 File: bastion-example-2.py
215 import Bastion
216 class Sample:
217 value = 0
218 def _set(self, value):
219 self.value = value
220 def setvalue(self, value):
221 if 10 < value <= 20:
222 self._set(value)
223 else:
224 raise ValueError, "illegal value"
225 def getvalue(self):
226 return self.value
227 #
228 # try it
229 def is_public(name):
230 return name[:3] != "get"
231 s = Bastion.Bastion(Sample(), is_public)
232 s._set(100) # this works
233 print s.getvalue() # but not this
234 100
235 Traceback (innermost last):
236 ...
237 AttributeError: getvalue
238 14.7. readline 模块
239 (可选) readline 模块使用 GNU readline 库(或兼容库)实现了 Unix 下增强的
240 输入编辑支持. 如 Example 14-9 所示.
241 该模块提供了增强的命令行编辑功能, 例如命令行历史等. 它还增强了 input
242 和 raw_input 函数.
243 14.7.0.1. Example 14-9. 使用 readline 模块
244 File: readline-example-1.py
245 import readline # activate readline editing
246 14.8. rlcompleter 模块
247 (可选, 只用于 Unix ) rlcompleter 模块为 readline 模块提供了单词自动完
248 成功能.
249 导入该模块就可以启动自动完成功能. 默认情况下完成函数被绑定在了 Esc 键
250 上. 按两次 Esc 键就可以自动完成当前单词. 你可以使用下面的代码修改所绑
251 定的键:
252 import readline
253 readline.parse_and_bind("tab: complete")
254 Example 14-10 展示了如何在程序中使用自动完成函数.
255 14.8.0.1. Example 14-10. 使用 rlcompleter 模块展开名字
256 File: rlcompleter-example-1.py
257 import rlcompleter
258 import sys
259 completer = rlcompleter.Completer()
260 for phrase in "co", "sys.p", "is":
261 print phrase, "=>",
262 # emulate readline completion handler
263 try:
264 for index in xrange(sys.maxint):
265 term = completer.complete(phrase, index)
266 if term is None:
267 break
268 print term,
269 except:
270 pass
271 print
272 co => continue compile complex coerce completer
273 sys.p => sys.path sys.platform sys.prefix
274 is => is isinstance issubclass
275 14.9. statvfs 模块
276 statvfs 模块包含一些与 os.statvfs (可选)函数配合使用的常量和函数, 该
277 函数会返回文件系统的相关信息. 如 Example 14-11 所示.
278 14.9.0.1. Example 14-11. 使用 statvfs 模块
279 File: statvfs-example-1.py
280 import statvfs
281 import os
282 st = os.statvfs(".")
283 print "preferred block size", "=>", st[statvfs.F_BSIZE]
284 print "fundamental block size", "=>", st[statvfs.F_FRSIZE]
285 print "total blocks", "=>", st[statvfs.F_BLOCKS]
286 print "total free blocks", "=>", st[statvfs.F_BFREE]
287 print "available blocks", "=>", st[statvfs.F_BAVAIL]
288 print "total file nodes", "=>", st[statvfs.F_FILES]
289 print "total free nodes", "=>", st[statvfs.F_FFREE]
290 print "available nodes", "=>", st[statvfs.F_FAVAIL]
291 print "max file name length", "=>", st[statvfs.F_NAMEMAX]
292 preferred block size => 8192
293 fundamental block size => 1024
294 total blocks => 749443
295 total free blocks => 110442
296 available blocks => 35497
297 total file nodes => 92158
298 total free nodes => 68164
299 available nodes => 68164
300 max file name length => 255
301 14.10. calendar 模块
302 calendar 模块是 Unix cal 命令的 Python 实现. 它可以将给定年份/月份的
303 日历输出到标准输出设备上.
304 prmonth(year, month) 打印给定月份的日历, 如 Example 14-12 所示.
305 14.10.0.1. Example 14-12. 使用 calendar 模块
306 File: calendar-example-1.py
307 import calendar
308 calendar.prmonth(1999, 12)
309 December 1999
310 Mo Tu We Th Fr Sa Su
311 1 2 3 4 5
312 6 7 8 9 10 11 12
313 13 14 15 16 17 18 19
314 20 21 22 23 24 25 26
315 27 28 29 30 31
316 prcal(year) 打印给定年份的日历, 如 Example 14-13 所示.
317 14.10.0.2. Example 14-13. 使用 calendar 模块
318 File: calendar-example-2.py
319 import calendar
320 calendar.prcal(2000)
321 2000
322 January February March
323 Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
324 Su
325 1 2 1 2 3 4 5 6 1 2 3
326 4 5
327 3 4 5 6 7 8 9 7 8 9 10 11 12 13 6 7 8 9 10 11
328 12
329 10 11 12 13 14 15 16 14 15 16 17 18 19 20 13 14 15 16 17 18
330 19
331 17 18 19 20 21 22 23 21 22 23 24 25 26 27 20 21 22 23 24 25
332 26
333 24 25 26 27 28 29 30 28 29 27 28 29 30 31
334 31
335 April May June
336 Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
337 Su
338 1 2 1 2 3 4 5 6 7 1 2
339 3 4
340 3 4 5 6 7 8 9 8 9 10 11 12 13 14 5 6 7 8 9 10
341 11
342 10 11 12 13 14 15 16 15 16 17 18 19 20 21 12 13 14 15 16 17
343 18
344 17 18 19 20 21 22 23 22 23 24 25 26 27 28 19 20 21 22 23 24
345 25
346 24 25 26 27 28 29 30 29 30 31 26 27 28 29 30
347 July August September
348 Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
349 Su
350 1 2 1 2 3 4 5 6 1
351 2 3
352 3 4 5 6 7 8 9 7 8 9 10 11 12 13 4 5 6 7 8 9
353 10
354 10 11 12 13 14 15 16 14 15 16 17 18 19 20 11 12 13 14 15 16
355 17
356 17 18 19 20 21 22 23 21 22 23 24 25 26 27 18 19 20 21 22 23
357 24
358 24 25 26 27 28 29 30 28 29 30 31 25 26 27 28 29 30
359 31
360 October November December
361 Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
362 Su
363 1 1 2 3 4 5 1
364 2 3
365 2 3 4 5 6 7 8 6 7 8 9 10 11 12 4 5 6 7 8 9
366 10
367 9 10 11 12 13 14 15 13 14 15 16 17 18 19 11 12 13 14 15 16
368 17
369 16 17 18 19 20 21 22 20 21 22 23 24 25 26 18 19 20 21 22 23
370 24
371 23 24 25 26 27 28 29 27 28 29 30 25 26 27 28 29 30
372 31
373 30 31
374 注意这里的日历是按照欧洲习惯打印的, 也就是说星期一是一个星期的第一天,
375 其他情况需要请参考模块中的几个类. (和咱们一样, 不用管了)
376 该模块中的其他类或函数可以帮助你输出自己需要的格式.
377 14.11. sched 模块
378 sched 模块为非线程环境提供了一个简单的计划任务模式. 如 Example 14-14
379 所示.
380 14.11.0.1. Example 14-14. 使用 sched 模块
381 File: sched-example-1.py
382 import sched
383 import time, sys
384 scheduler = sched.scheduler(time.time, time.sleep)
385 # add a few operations to the queue
386 scheduler.enter(0.5, 100, sys.stdout.write, ("one\n",))
387 scheduler.enter(1.0, 300, sys.stdout.write, ("three\n",))
388 scheduler.enter(1.0, 200, sys.stdout.write, ("two\n",))
389 scheduler.run()
390 one
391 two
392 three
393 14.12. statcache 模块
394 statcache 模块提供了访问文件相关信息的相关函数. 它是 os.stat 的扩展模
395 块, 而且它会缓存收集到的信息. 如 Example 14-15 所示.
396 2.2 后该模块被废弃, 请使用 os.stat() 函数代替, 原因很简单, 它导致了更
397 复杂的缓存管理, 反而降低了性能.
398 14.12.0.1. Example 14-15. 使用 statcache 模块
399 File: statcache-example-1.py
400 import statcache
401 import os, stat, time
402 now = time.time()
403 for i in range(1000):
404 st = os.stat("samples/sample.txt")
405 print "os.stat", "=>", time.time() - now
406 now = time.time()
407 for i in range(1000):
408 st = statcache.stat("samples/sample.txt")
409 print "statcache.stat", "=>", time.time() - now
410 print "mode", "=>", oct(stat.S_IMODE(st[stat.ST_MODE]))
411 print "size", "=>", st[stat.ST_SIZE]
412 print "last modified", "=>", time.ctime(st[stat.ST_MTIME])
413 os.stat => 0.371000051498
414 statcache.stat => 0.0199999809265
415 mode => 0666
416 size => 305
417 last modified => Sun Oct 10 18:39:37 1999
418 14.13. grep 模块
419 grep 模块提供了在文本文件中搜索字符串的另种方法, 如 Example 14-16 所
420 示.
421 版本 2.1 时被声明不支持, 及就是说, 当前版本已经无法使用该模块.
422 14.13.0.1. Example 14-16. 使用 grep 模块
423 File: grep-example-1.py
424 import grep
425 import glob
426 grep.grep("\<rather\>", glob.glob("samples/*.txt"))
427 # 4: indentation, rather than delimiters, might become
428 14.14. dircache 模块
429 (已经废弃) 与 statcache 类似, 该模块是 os.listdir 函数的一个扩展, 提
430 供了缓存支持, 可能因为同样的原因被废弃吧~ MUHAHAHAHAHA~~~~ . 请使用
431 os.listdir 代替. 如 Example 14-17 所示.
432 14.14.0.1. Example 14-17. 使用 dircache 模块
433 File: dircache-example-1.py
434 import dircache
435 import os, time
436 #
437 # test cached version
438 t0 = time.clock()
439 for i in range(100):
440 dircache.listdir(os.sep)
441 print "cached", time.clock() - t0
442 #
443 # test standard version
444 t0 = time.clock()
445 for i in range(100):
446 os.listdir(os.sep)
447 print "standard", time.clock() - t0
448 cached 0.0664509964968
449 standard 0.5560845807
450 14.15. dircmp 模块
451 (已废弃, 只用于 1.5.2) dircmp 模块用于比较两个目录的内容, 如 Example
452 14-18 所示.
453 14.15.0.1. Example 14-18. 使用 dircmp 模块
454 File: dircmp-example-1.py
455 import dircmp
456 d = dircmp.dircmp()
457 d.new("samples", "oldsamples")
458 d.run()
459 d.report()
460 diff samples oldsamples
461 Only in samples : ['sample.aiff', 'sample.au', 'sample.wav']
462 Identical files : ['sample.gif', 'sample.gz', 'sample.jpg', ...]
463 Python 2.0 后, 该模块被 filecmp 替换.
464 14.16. cmp 模块
465 (已废弃, 只用于 1.5.2) cmp 模块用于比较两个文件, 如 Example 14-19 所
466 示.
467 14.16.0.1. Example 14-19. 使用 cmp 模块
468 File: cmp-example-1.py
469 import cmp
470 if cmp.cmp("samples/sample.au", "samples/sample.wav"):
471 print "files are identical"
472 else:
473 print "files differ!"
474 files differ!
475 Python 2.0 后, 该模块被 filecmp 替换.
476 14.17. cmpcache 模块
477 (已废弃, 只用于 1.5.2) cmpcache 模块用于比较两个文件. 它是 cmp 模块的
478 扩展, 提供了缓存支持. 如 Example 14-20 所示.
479 14.17.0.1. Example 14-20. 使用 cmpcache 模块
480 File: cmpcache-example-1.py
481 import cmpcache
482 if cmpcache.cmp("samples/sample.au", "samples/sample.wav"):
483 print "files are identical"
484 else:
485 print "files differ!"
486 files differ!
487 Python 2.0 后, 该模块被 filecmp 替换.
488 但 filecmp 已经不提供缓存支持.
489 14.18. util 模块
490 (已废弃, 只用于 1.5.2) util 模块提供了常见操作的封装函数. 新代码可以
491 使用如 Examples 14-21 到 14-23 的实现方法.
492 Example 14-21 展示了 remove(sequence, item) 函数.
493 14.18.0.1. Example 14-21. 实现 util 模块的 remove 函数
494 File: util-example-1.py
495 def remove(sequence, item):
496 if item in sequence:
497 sequence.remove(item)
498 Example 14-22 展示了 readfile(filename) => string 函数.
499 14.18.0.2. Example 14-22. 实现 util 模块的 readfile 函数
500 File: util-example-2.py
501 def readfile(filename):
502 file = open(filename, "r")
503 return file.read()
504 Example 14-23 展示了 `readopenfile(file) => string 函数.
505 14.18.0.3. Example 14-23. 实现 util 模块的 readopenfile 函数
506 File: util-example-3.py
507 def readopenfile(file):
508 return file.read()
509 14.19. soundex 模块
510 (已废弃, 只用于 1.5.2) soundex 实现了一个简单的 hash 算法, 基于英文发
511 音将单词转换为 6 个字符的字符串.
512 版本 2.0 后, 该模块已从标准库中删除.
513 get_soundex(word) 返回给定单词的 soundex 字符串. sound_similar(word1,
514 word2) 判断两个单词的 soundex 是否相同. 一般说来发音相似的单词有相同
515 的 soundex . 如 Example 14-24 所示.
516 14.19.0.1. Example 14-24. 使用 soundex 模块
517 File: soundex-example-1.py
518 import soundex
519 a = "fredrik"
520 b = "friedrich"
521 print soundex.get_soundex(a), soundex.get_soundex(b)
522 print soundex.sound_similar(a, b)
523 F63620 F63620
524 1
525 14.20. timing 模块
526 (已废弃, 只用于 Unix ) timing 用于监控 Python 程序的执行时间. 如
527 Example 14-25 所示.
528 14.20.0.1. Example 14-25. 使用 timing 模块
529 File: timing-example-1.py
530 import timing
531 import time
532 def procedure():
533 time.sleep(1.234)
534 timing.start()
535 procedure()
536 timing.finish()
537 print "seconds:", timing.seconds()
538 print "milliseconds:", timing.milli()
539 print "microseconds:", timing.micro()
540 seconds: 1
541 milliseconds: 1239
542 microseconds: 1239999
543 你可以按照 Example 14-26 中的方法用 time 模块实现 timing 模块的功能.
544 14.20.0.2. Example 14-26. 模拟 timing 模块
545 File: timing-example-2.py
546 import time
547 t0 = t1 = 0
548 def start():
549 global t0
550 t0 = time.time()
551 def finish():
552 global t1
553 t1 = time.time()
554 def seconds():
555 return int(t1 - t0)
556 def milli():
557 return int((t1 - t0) * 1000)
558 def micro():
559 return int((t1 - t0) * 1000000)
560 time.clock() 可以替换 time.time() 获得 CPU 时间.
561 14.21. posixfile 模块
562 (已废弃, 只用于 Unix ) posixfile 提供了一个类文件的对象( file-like
563 object ), 实现了文件锁定的支持. 如 Example 14-27 所示. 新程序请使用
564 fcntl 模块代替.
565 14.21.0.1. Example 14-27. 使用 posixfile 模块
566 File: posixfile-example-1.py
567 import posixfile
568 import string
569 filename = "counter.txt"
570 try:
571 # open for update
572 file = posixfile.open(filename, "r+")
573 counter = int(file.read(6)) + 1
574 except IOError:
575 # create it
576 file = posixfile.open(filename, "w")
577 counter = 0
578 file.lock("w|", 6)
579 file.seek(0) # rewind
580 file.write("%06d" % counter)
581 file.close() # releases lock
582 14.22. bisect 模块
583 bisect 模块用于向排序后的序列插入对象.
584 insort(sequence, item) 将条目插入到序列中, 并且保证序列的排序. 序列可
585 以是任意实现了 _ _getitem_ _ 和 insert 方法的序列对象. 如 Example
586 14-28 所示.
587 14.22.0.1. Example 14-28. 使用 bisect 模块向列表插入条目
588 File: bisect-example-1.py
589 import bisect
590 list = [10, 20, 30]
591 bisect.insort(list, 25)
592 bisect.insort(list, 15)
593 print list
594 [10, 15, 20, 25, 30]
595 bisect(sequence, item) => index 返回条目插入后的索引值, 不对序列做任何
596 修改. 如 Example 14-29 所示.
597 14.22.0.2. Example 14-29. 使用 bisect 模块获得插入点位置
598 File: bisect-example-2.py
599 import bisect
600 list = [10, 20, 30]
601 print list
602 print bisect.bisect(list, 25)
603 print bisect.bisect(list, 15)
604 [10, 20, 30]
605 2
606 1
607 14.23. knee 模块
608 knee 模块用于 Python 1.5 中导入包( package import )的实现. 当然 Python
609 解释器已经支持了这个, 所以这个模块几乎没有什么作用, 不过你可以看看它
610 的代码, 明白这一切是怎么完成的.
611 代码请参见 Python-X.tgz\Python-2.4.4\Demo\imputil\knee.py
612 当然, 你可以导入该模块,如 Example 14-30 所示.
613 14.23.0.1. Example 14-30. 使用 knee 模块
614 File: knee-example-1.py
615 import knee
616 # that's all, folks!
617 14.24. tzparse 模块
618 (已废弃) tzparse 模块用于解析时区标志( time zone specification ). 导入
619 时它会自动分析 TZ 环境变量. 如 Example 14-31 所示.
620 14.24.0.1. Example 14-31. 使用 tzparse 模块
621 File: tzparse-example-1.py
622 import os
623 if not os.environ.has_key("TZ"):
624 # set it to something...
625 os.environ["TZ"] = "EST+5EDT;100/2,300/2"
626 # importing this module will parse the TZ variable
627 import tzparse
628 print "tzparams", "=>", tzparse.tzparams
629 print "timezone", "=>", tzparse.timezone
630 print "altzone", "=>", tzparse.altzone
631 print "daylight", "=>", tzparse.daylight
632 print "tzname", "=>", tzparse.tzname
633 tzparams => ('EST', 5, 'EDT', 100, 2, 300, 2)
634 timezone => 18000
635 altzone => 14400
636 daylight => 1
637 tzname => ('EST', 'EDT')
638 除了这些变量之外, 该模块还提供了一些用于时间计算的函数.
639 14.25. regex 模块
640 (已废弃) regex 模块是旧版本的(1.5 前)正则表达式模块, 用法如 Example
641 14-32 所示. 新代码请使用 re 模块实现.
642 注意在 Python 1.5.2 中 regex 比 re 模块要快. 但在新版本中 re 模块更
643 快.
644 14.25.0.1. Example 14-32. 使用 regex 模块
645 File: regex-example-1.py
646 import regex
647 text = "Man's crisis of identity in the latter half of the 20th century"
648 p = regex.compile("latter") # literal
649 print p.match(text)
650 print p.search(text), repr(p.group(0))
651 p = regex.compile("[0-9]+") # number
652 print p.search(text), repr(p.group(0))
653 p = regex.compile("\<\w\w\>") # two-letter word
654 print p.search(text), repr(p.group(0))
655 p = regex.compile("\w+$") # word at the end
656 print p.search(text), repr(p.group(0))
657 -1
658 32 'latter'
659 51 '20'
660 13 'of'
661 56 'century'
662 14.26. regsub 模块
663 (已废弃) regsub 模块提供了基于正则表达式的字符串替换操作. 用法如
664 Example 14-33 所示. 新代码请使用 re 模块中的 replace 函数代替.
665 14.26.0.1. Example 14-33. 使用 regsub 模块
666 File: regsub-example-1.py
667 import regsub
668 text = "Well, there's spam, egg, sausage, and spam."
669 print regsub.sub("spam", "ham", text) # just the first
670 print regsub.gsub("spam", "bacon", text) # all of them
671 Well, there's ham, egg, sausage, and spam.
672 Well, there's bacon, egg, sausage, and bacon.
673 14.27. reconvert 模块
674 (已废弃) reconvert 提供了旧样式正则表达式( regex 模块中使用)到新样式
675 ( re 模块)的转换工具. 如 Example 14-34 所示. 它也可以作为一个命令行工
676 具.
677 14.27.0.1. Example 14-34. 使用 reconvert 模块
678 File: reconvert-example-1.py
679 import reconvert
680 for pattern in "abcd", "a\(b*c\)d", "\<\w+\>":
681 print pattern, "=>", reconvert.convert(pattern)
682 abcd => abcd
683 a\(b*c\)d => a(b*c)d
684 \<\w+\> => \b\w+\b
685 14.28. regex_syntax 模块
686 (已废弃) regex_syntax 模块用于改变正则表达式的模式, 如 Example 14-35
687 所示.
688 14.28.0.1. Example 14-35. 使用 regex_syntax 模块
689 File: regex-syntax-example-1.py
690 import regex_syntax
691 import regex
692 def compile(pattern, syntax):
693 syntax = regex.set_syntax(syntax)
694 try:
695 pattern = regex.compile(pattern)
696 finally:
697 # restore original syntax
698 regex.set_syntax(syntax)
699 return pattern
700 def compile_awk(pattern):
701 return compile(pattern, regex_syntax.RE_SYNTAX_AWK)
702 def compile_grep(pattern):
703 return compile(pattern, regex_syntax.RE_SYNTAX_GREP)
704 def compile_emacs(pattern):
705 return compile(pattern, regex_syntax.RE_SYNTAX_EMACS)
706 14.29. find 模块
707 (已废弃, 只用于 1.5.2) find 模块用于在给定目录及其子目录中查找符合给
708 定匹配模式的文件, 如 Example 14-36 所示.
709 匹配模式的语法与 fnmatch 中相同.
710 14.29.0.1. Example 14-36. 使用 find 模块
711 File: find-example-1.py
712 import find
713 # find all JPEG files in or beneath the current directory
714 for file in find.find("*.jpg", "."):
715 print file
716 .\samples\sample.jpg