python第六天 函數 python標準庫實例大全

今天學習第一模塊的最後一課課程--函數:html

python的第一個函數:node

1 1 def func1():
2 2     print('第一個函數')
3 3     return 0
4 4 func1()
1

同時返回多種類型時,將是返回一元組:python

1 1 def func2():
2 2     return 1,"",[3,'4'],{'':'','':8}#返回多種數據類型
3 3 data=func2()
4 4 print(data)
2

函數參數的調用:react

1,位置調用:編寫時須要一一對應,若是少了,或是多少都會出錯!linux

1 1 def func3(x,y):
2 2     z=x+y
3 3     return z
4 4 
5 5 print(func3(1,2,3))#參數不對,報錯
3

2,關鍵字調用:ios

1 1 def func3(x,y):
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)#能夠不對應位置
4

3,位置調用與關鍵字調用能夠同時使用,可是須要注意的問題:git

1 1 def func4(x,y,z):
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)#錯誤的調用
5

參數組:程序員

使用參數組能夠傳值列表,字典:格式  web

1 1 def func5(x,*args,**kwargs):
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 #列表參數是特殊的位置參數,能夠不傳值, 字典是特殊的關鍵字參數
View Code

全局變量與局部變量的做用域:正則表達式

 1  1 def func6():
 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)
View Code
 1  1 def func8(name,n):
 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)#全局列表,字典被修改,整數與字符串不能被修改
View Code

哈哈,明天開始做業啦!做業好難感受! 

  1 默認標準庫位置(安裝位置不一樣請本身更換)
  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:Base1六、Base3二、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程序庫
Python3標準庫中文翻譯
   1 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
 514exec 函數 (如 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 函數引起. 若是它在最頂層沒有
 657try-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-451275 示.
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-481332 示了另外一種方法. 這裏 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-872317 示.
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 的版本相同.
python標準庫實例-1核心模塊
   1 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
python標準庫實例-2標準模塊 
  1 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
python標準庫實例-3線程和進程
  1 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-22498 示.
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'
python標準庫實例-4數據表示
  1 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 (&quot;character data&quot;), tags, and
 33 entities.
 34 </body>
 35 </document>
 36 在這個例子中, <document> , <header> , 以及 <body> 是起始標籤. 每一個起始
 37 標籤都有一個對應的結束標籤, 使用斜線 "/ " 標記. 起始標籤能夠包含多個
 38 屬性, 好比這裏的 name 屬性.
 39 起始標籤和它對應的結束標籤中的任何東西被稱爲 元素( element ) . 這裏
 40 document 元素包含 header 和 body 兩個元素.
 41 &quot; 是一個字符實體( character entity ). 字符實體用於在文本區域中表
 42 示特殊的保留字符, 使用 & 指示. 這裏它表明一個引號, 常見字符實體還有 "
 43 < ( &lt; ) "" > ( &gt; ) " .
 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-1220 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 &mdash; 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("&lt;spam&amp;eggs&gt;")
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 &lt;spam&amp;eggs&gt;
558 &aring; i &aring;a &auml; e &ouml;
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-14595 示.
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.
python標準庫實例-5文件格式
  1 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()
python標準庫實例-6郵件和新聞消息處理 
   1 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 =\
相關文章
相關標籤/搜索