《Python3.6官方文件》– 第十一章
第二部分涵蓋了更高階的模組,支援更專業的程式設計需求,這些模組很少出現在小的指令碼中。
格式化輸出
提供一系列 對很大或深度層疊的容器進行定製化的壓縮展示。
import reprlib reprlib.repr(set('supercalifragilisticexpialidocious'))
提供更成熟的控制,將內建物件和使用者定義物件更易讀地打印出來,當結果長於一行時,”pretty printer”新增行數和縮排來將資料結構更清楚地展現出來。
import pprint t = [[[['black', 'cyan'], 'white', ['green', 'red']], [['magenta','yellow'], 'blue']]] pprint.pprint(t, width=30)
textwrap
格式化文字段落為合適當前螢幕的寬度
import textwrap doc = """The wrap() method is just like fill() except that it returns a list of strings instead of one big string with newlines to separate the wrapped lines.""" print(textwrap.fill(doc, width=40))
local
為各種資料格式的資料庫提供統一的訪問入口,local的格式化功能的group屬性提供了一種用組分隔符直接分隔數字的方式。
import locale locale.setlocale(locale.LC_ALL, 'English_United States.1252') conv = locale.localeconv() # get a mapping of conventions x = 1234567.8 locale.format("%d", x, grouping=True) locale.format_string("%s%.*f", (conv['currency_symbol'],conv['frac_digits'], x), grouping=True
模板
string
包含了一個多功能的 Template
類,通過它使用者可以通過合適的語法進行編輯操作,它允許使用者在不對應用做修改的方式進行定製化調整。
模板使用$
和Python有效識別符號(數字,字母,下劃線)組合形式的佔位符名稱,帶有{}的佔位符後可以追加沒有空格的字元數字和字母,在文字中使用單個$需要在模板中輸入$$
from string import Template t = Template('${village}folk send $$10 to $cause.') t.substitute(village='Nottingham', cause='the ditch fund')
當字典或關鍵引數沒有提供佔位符對應的資料時,substitute()
會產生一個KeyError
,對mail-merge風格的應用,使用者提供的資料可能是不完整的,這時safe_substitute()
是更合適的-如果資料缺失,它將保持佔位符不變
t = Template('Return the $item to $owner.') d = dict(item='unladen swallow') t.substitute(d) t.safe_substitute(d)
模板子類可以指定自定義分隔符。例如,照片瀏覽器的批量重新命名程式可以選擇使用百分比符號做佔位符,例如當前日期、影象序列號或檔案格式:
import time, os.path photofiles = ['img_1074.jpg', 'img_1076.jpg', 'img_1077.jpg'] class BatchRename(Template): delimiter = '%' fmt = input('Enter rename style (%d-date %n-seqnum %f-format): ') t = BatchRename(fmt) date = time.strftime('%d%b%y') for i, filename in enumerate(photofiles): base, ext = os.path.splitext(filename) newname = t.substitute(d=date, n=i, f=ext) print('{0} --> {1}'.format(filename, newname))
模板的另一個實用功能是將邏輯處理和複雜的輸出細節分離開來,可以將模板替換為XML檔案、純文字報告和HTML Web報表等多種形式
二進位制資料記錄設計
struct
提供 pack()
和 unpack()
,用於處理可變長度二進位制記錄格式.下邊的例子示範了在不使用zipfile
的情況下迴圈使用zip的頭資訊.H
和I
分別代表了2位元組和4位元組無符號數,<
標示它們使用little-endian位元組的標準大小進行排序順序
import struct with open('myfile.zip', 'rb') as f: data = f.read() start = 0 for i in range(3): # show the first 3 file headers start += 14 fields = struct.unpack('<IIIHH', data[start:start+16]) crc32, comp_size, uncomp_size, filenamesize, extra_size = fields start += 16 filename = data[start:start+filenamesize] start += filenamesize extra = data[start:start+extra_size] print(filename, hex(crc32), comp_size, uncomp_size) start += extra_size + comp_size # skip to the next header
多執行緒
執行緒是為了對沒有順序依賴的任務進行解耦.在其他任務在後臺執行時,執行緒可以用來提高當前應用程式的響應.一個相關的使用場景就是一個執行緒與另一個執行緒並行I/O計算.
下邊的程式碼示範瞭如何通過threading
在主程在執行的情況下如何在後臺執行任務
import threading, zipfile class AsyncZip(threading.Thread): def __init__(self, infile, outfile): threading.Thread.__init__(self) self.infile = infile self.outfile = outfile def run(self): f = zipfile.ZipFile(self.outfile, 'w', zipfile.ZIP_DEFLATED) f.write(self.infile) f.close() print('Finished background zip of:', self.infile) background = AsyncZip('mydata.txt', 'myarchive.zip') background.start() print('The main program continues to run in foreground.') background.join() # Wait for the background task to finish print('Main program waited until background was done.')
多執行緒應用程式的主要挑戰是協調共享資料或其它資源。為此,threading提供了許多同步基元,包括locks, events, condition variables和 semaphores。
儘管這些工具是強大的,但較小的設計錯誤可能會導致難以復現的問題產生。因此,任務協調的首選方法是將所有資源訪問集中到單個執行緒中,然後使用queue
為來自其他執行緒的請求提供反饋。應用使用Queue
物件使執行緒間通訊和協調更容易設計,更可讀,更可靠。
Logging
logging
提供了一個功能齊全並易拓展的日誌系統,在這個例子中,log資訊被髮送到一個檔案或sys.stderr
中
import logging logging.debug('Debugging information') logging.info('Informational message') logging.warning('Warning:config file %s not found', 'server.conf') logging.error('Error occurred') logging.critical('Critical error -- shutting down')
產生如下輸出
WARNING:root:Warning:config file server.conf not found ERROR:root:Error occurred CRITICAL:root:Critical error -- shutting down
預設情況下,資訊和除錯資訊被抑制,輸出被髮送到標準錯誤中,其他輸出選項包括通過電子郵件、資料報、套接字或HTTP伺服器對訊息進行路由,新的過濾器可以根據訊息優先順序選擇不同的路由:DEBUG, INFO, WARNING, ERROR, 和 CRITICAL。
日誌系統可以直接通過Python進行配置,或在不修改程式的前提下通過載入使用者編輯的配置檔案進行定製配置
弱引用
Python的自動記憶體管理(對多數物件進行引用計數,並由garbage-collection
進行迴圈刪除)記憶體在最後使用後不久就被釋放了。
這種方法已經對大多數程式都適用了,但有時需要追蹤物件被其他物件的使用情況,不幸的是,僅僅是追蹤這些物件所建立的引用就會使得這些引用變成永久性的。weakref
提供一些工具,使得當追蹤這些物件時不需要建立引用,當物件不再被需要時,它被自動從weakref表中刪除,並觸發弱引用物件回撥,典型應用是快取那些建立成本高的物件
import weakref, gc class A: def __init__(self, value): self.value = value def __repr__(self): return str(self.value) a = A(10) # create a reference d = weakref.WeakValueDictionary() d['primary'] = a # does not create a reference d['primary'] # fetch the object if it is still alive del a # remove the one reference gc.collect() # run garbage collection right away d['primary'] # entry was automatically removed
Lists 工具
很多資料結構需求可以通過內建的list來滿足,有時,也需要根據實現的不同表現進行替換。
array
提供array()
物件,它就像一個能以更緊湊地儲存同質資料的list,下邊的例子展示了一組2位元組的無符號二進位制數的儲存(typecode:H),而不是常規的16位元組
from array import array a = array('H', [4000, 10, 700, 22222]) sum(a) a[1:3]
collections
提供一個deque()
物件,它就像是可以在兩端快速add,pop,但讀取中間資料慢的list,這個物件更適合實現佇列和廣度優先的樹
from collections import deque d = deque(["task1", "task2", "task3"]) d.append("task4") print("Handling", d.popleft()) unsearched = deque([starting_node]) def breadth_first_search(unsearched): node = unsearched.popleft() for m in gen_moves(node): if is_goal(m): return m unsearched.append(m)
除了替代list的實現外,這個庫還提供其他工具,bisect
提供控制list排序的功能
import bisect scores = [(100, 'perl'), (200, 'tcl'), (400, 'lua'), (500, 'python')] bisect.insort(scores, (300, 'ruby')) scores
heapq
為常見的list實現了堆功能,最小的元素總會在0位上,這對那些總需要找到最小元素但又不想每次對list進行排序的應用來說是很有用的
from heapq import heapify, heappop, heappush data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0] heapify(data) # rearrange the list into heap order heappush(data, -5) # add a new entry [heappop(data) for i in range(3)] # fetch the three smallest entries
十進位制浮點運算
decimal
提供Decimal
資料型別來進行十進位制浮點運算,和內建的二進位制浮點實現float
相比,它在以下方面更有幫助
- 需要準確表示十進位制的金融或其他應用
- 精度控制
- 控制舍入以符合規定要求
- 追蹤有意義的精度
- 期望匹配人工計算結果
例如,計算一個70美分的電話費用的5%的稅在十進位制浮點和二進位制浮點上會給出不同的結果。如果結果被舍入到最近的分值,則差異變得顯著:
from decimal import * round(Decimal('0.70') * Decimal('1.05'), 2) round(.70 * 1.05, 2)
Decimal 結果在尾部追加一個0,Decimal複製手工數學計算,避免了二進位制無法精確表示十進位制精度帶來的問題
精確表示使得十進位制類能夠執行那些不適合二進位制浮點的模運算的相等性測試:
Decimal('1.00') % Decimal('.10') 1.00 % 0.10 sum([Decimal('0.1')]*10) == Decimal('1.0') sum([0.1]*10) == 1.0
getcontext().prec = 36 Decimal(1) / Decimal(7)