Chuyến đi thứ hai này bao hàm những module nâng cao hơn sẽ hỗ trợ cho các nhu cầu lập trình chuyên nghiệp. Những module này hiếm khi xuất hiện trong các đoạn mã nhỏ.
Module reprlib
cung cấp một phiên bản tùy chỉnh của repr()
cho những hiện thị rút gọn của những phần tử chứa(containers) lớn:
>>> import reprlib
>>> reprlib.repr(set('supercalifragilisticexpialidocious'))
"{'a', 'c', 'd', 'e', 'f', 'g', ...}"
Module pprint
hỗ trợ kiểm soát tinh vi hơn qua việc xuất cả những đối tượng có sẵn và được người dùng định nghĩa. Khi kết quả dài hơn một dòng, “pretty printer” thêm vào dòng trống và căn lề để cấu trúc dữ liệu hiển thị rõ ràng hơn:
>>> import pprint
>>> t = [[[['black', 'cyan'], 'white', ['green', 'red']], [['magenta',
... 'yellow'], 'blue']]]
...
>>> pprint.pprint(t, width=30)
[[[['black', 'cyan'],
'white',
['green', 'red']],
[['magenta', 'yellow'],
'blue']]]
Module textwrap
định dạng đoạn văn bản cho phù hợp với chiều rộng màn hình hiển thị cho trước:
>>> 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))
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.
Module locale
truy cập vào một cơ sở dữ liệu của các định dạng dữ liệu cụ thể theo văn hóa. Thuộc tính nhóm của hàm định dạng của locale cung cấp một cách thức trực tiếp cho việc định dạng số với các phân cách nhóm:
>>> import locale
>>> locale.setlocale(locale.LC_ALL, 'English_United States.1252')
'English_United States.1252'
>>> conv = locale.localeconv() # lấy về một bản đồ các quy ước
>>> x = 1234567.8
>>> locale.format("%d", x, grouping=True)
'1,234,567'
>>> locale.format_string("%s%.*f", (conv['currency_symbol'],
... conv['frac_digits'], x), grouping=True)
'$1,234,567.80'
Module string
bao gồm một lớp (class) đa năng Template
với cú pháp được đơn giản hóa phù hợp cho việc chỉnh sửa của người dùng cuối(end-user). Việc này cho phép người dùng tùy chỉnh các ứng dụng mà không cần phải thay thế.
Định dạng sử dụng các tên giữ chỗ(placeholder) biểu thị bởi $
với các định danh hợp lệ của Python (chữ số và dấu gạch dưới). Sử dụng dấu ngoặc nhọn { }
cho placeholder cho phép nhiều kí tự chữ số theo sau nó mà không cần có dấu cách. Việc sử dụng $$
trả về $
, tức là bỏ qua chức năng của $
trong cú pháp, hiểu như là một ký tự (tương tự escape \
trong Linux shell):
>>> from string import Template
>>> t = Template('${village}folk send $$10 to $cause.')
>>> t.substitute(village='Nottingham', cause='the ditch fund')
'Nottinghamfolk send $10 to the ditch fund.'
Phương pháp substitute()
tạo ra một KeyError
khi một placeholder không được hỗ trợ trong từ điển hoặc đối số từ khóa. Cho những ứng dụng kiểu như tổng hợp mail, dữ liệu được cung cấp có thể chưa hoàn chỉnh và phương pháp safe_substitute()
có thể phù hợp hơn — nó sẽ giữ nguyên placeholders nếu dữ liệu bị thiếu:
>>> t = Template('Return the $item to $owner.')
>>> d = dict(item='unladen swallow')
>>> t.substitute(d)
Traceback (most recent call last):
...
KeyError: 'owner'
>>> t.safe_substitute(d)
'Return the unladen swallow to $owner.'
Các lớp phụ của Template có thể chỉ rõ dấu phân cách tùy chỉnh. Ví dụ, một tiện ích đổi tên hàng loạt cho một trình ảnh có thể chọn sử dụng dấu phần trăm %
cho placeholder như ngày hiện tại, số thứ tự ảnh, hoặc định dạng file:
>>> 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): ')
Enter rename style (%d-date %n-seqnum %f-format): Ashley_%n%f
>>> 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))
img_1074.jpg --> Ashley_0.jpg
img_1076.jpg --> Ashley_1.jpg
img_1077.jpg --> Ashley_2.jpg
Ứng dụng khác cho khuôn mẫu là phân chia logic chương trình từ những chi tiết của các định dạng đa ngõ ra. Điều này khiến nó khả dụng cho các khuôn mẫu tùy chỉnh thay thế ở các files XML, báo cáo văn bản, và báo cáo web HTML.
Module struct
cung cấp các hàm pack()
và unpack()
cho quá trình làm việc với các định dạng bản ghi nhị phân có chiều dài thay đổi được. Ví dụ tiếp theo chỉ ra cách lặp thông qua thông tin đầu (header information) trong một file ZIP mà không sử dụng module zipfile
. Các mã đóng gói "H"
và "I"
đại diện cho 2 và 4 byte số không dấu. Kí hiệu "<"
mô tả nó đang ở kích thước tiêu chuẩn và theo thứ tự byte là little-endian:
import struct
with open('myfile.zip', 'rb') as f:
data = f.read()
start = 0
for i in range(3): # chỉ đến 3 header đầu tiên của file
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 # bỏ qua cho đến header tiếp theo
Threading là một kỹ thuật tách các tác vụ không phụ thuộc một cách tuần tự. Các Thread có thể được sử dụng để cải thiện phản hồi của các ứng dụng chấp nhận ngõ vào của người dùng trong lúc các tác vụ khác chạy nền. Một cách dùng liên quan là thực hiện nhập/xuất (I/O) đồng thời với tính toán ở thread khác.
Đoạn mã dưới đây mô tả cách module bậc cao threading
có thể chạy các tác vụ nền trong khi chương trình chính tiếp tục hoạt động:
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() # đợi tác vụ chạy nền hoàn tất
print('Main program waited until background was done.')
Thử thách chính của các ứng dụng multi-threading là phối hợp các thread chia sẻ dữ liệu hoặc các tài nguyên khác. Cho việc này, module threading cung cấp một số sự đồng bộ cơ bản như khóa(locks), sự kiện(events), biến điều kiện(condition variables), và cờ hiệu(semaphores).
Trong khi những công cụ này hữu hiệu, những lỗi thiết kế nhỏ có thể dẫn đến những vấn đề khó để làm lại. Vì vậy, hướng tiếp cận tốt hơn cho việc phối hợp các tác vụ là tập trung tất cả truy cập đến một tài nguyên trong một thread đơn lẻ và sau đó sử dụng module hàng đợi (queue
) để cung cấp cho thread đó những yêu cầu từ các thread khác. Những ứng dụng sử dụng đối tượng Queue
cho việc giao tiếp và phối hợp giữa các thread dễ dàng hơn để thiết kế, dễ đọc hơn và tin cậy hơn.
Module logging
cho phép một hệ thống ghi nhật ký đầy đủ tính năng và linh hoạt. Một cách đơn giản nhất, các đoạn log được gửi đến một file hoặc mặc định đến 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')
Đoạn mã này xuất ra:
WARNING:root:Warning:config file server.conf not found
ERROR:root:Error occurred
CRITICAL:root:Critical error -- shutting down
Mặc định, các tin nhắn thông tin và sửa lỗi (debug) bị chặn lại và ngõ ra được gửi đến lỗi chuẩn (standard error). Những lựa chọn ngõ ra khác bao gồm các tin nhắn định tuyến qua e-mail, sơ đồ dữ liệu (datagram), sockets, hoặc đến một máy chủ HTTP. Những bộ lọc mới có thể lựa chọn định tuyến khác nhau dựa trên mức độ ưu tiên của tin nhắn: DEBUG
, INFO
, WARNING
, ERROR
, and CRITICAL
.
Hệ thống logging có thể được cấu hình trực tiếp từ Python hoặc được nạp từ một file cấu hình người dùng chỉnh sửa cho việc tùy chỉnh logging mà không cần thay thế ứng dụng.
Python thực hiện quản lý bộ nhớ tự động (việc đếm tham khảo cho phần lớn đối tượng và quá trình giải phóng bộ nhớ garbage collection để loại bỏ các chu kì). Bộ nhớ được giải phóng gần như sau khi tham khảo gần nhất đến nó bị loại bỏ.
Việc tiếp cận này hoạt động ổn cho hầu hết các ứng dụng nhưng thỉnh thoảng có một nhu cầu cho việc theo dấu đối tượng miễn cho chúng đang được sử dụng đâu đó. Nhưng mà, chỉ theo dấu đối tượng lại tạo ra tham khảo làm cho nó mang tính chất lâu dài. Module weakref
cung cấp các công cụ cho việc theo dấu đối tượng mà không tạo ra tham khảo. Khi đối tượng không còn cần thiết nữa, nó tự động xóa khỏi bảng weakref và một tín hiệu gọi về(callback) được kích(trigger) cho các đối tượng weakref. Những ứng dụng điển hình bao gồm đối tượng bộ nhớ đệm(cache) là rất xa xỉ để khởi tạo:
>>> import weakref, gc
>>> class A:
... def __init__(self, value):
... self.value = value
... def __repr__(self):
... return str(self.value)
...
>>> a = A(10) # tạo ra một tham khảo
>>> d = weakref.WeakValueDictionary()
>>> d['primary'] = a # không tạo tham khảo
>>> d['primary'] # dẫn đến đối tượng nếu nó vẫn còn tồn tại
10
>>> del a # xóa phần tử tham khảo
>>> gc.collect() # chạy garbage collection
0
>>> d['primary'] # cổng đã được tự động xóa bỏ
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
d['primary']
File "C:/python36/lib/weakref.py", line 46, in __getitem__
o = self.data[key]()
KeyError: 'primary'
Nhiều nhu cầu cấu trúc dữ liệu có thể phù hợp với những loại danh sách được xây dựng sẵn. Tuy nhiên, thỉnh thoảng sẽ có nhu cầu cho việc triển khai thay thế với các sự cân bằng về hiệu suất khác nhau.
Module array
cung cấp một đối tượng array()
giống như một list chỉ chứa dữ liệu đồng nhất và nhỏ gọn hơn. Ví dụ dưới đây mô tả một mảng các số được lưu trữ dưới dạng nhị phân không dấu 2byte (loại mã "H"
) hơn là 16byte thường dùng trên một ngõ vào cho các danh sách có quy tắc của các đối tượng int trong Python:
>>> from array import array
>>> a = array('H', [4000, 10, 700, 22222])
>>> sum(a)
26932
>>> a[1:3]
array('H', [10, 700])
Module collections
cung cấp một đối tượng deque()
giống như một list với việc thêm vào và lấy ra từ bên trái nhanh chóng nhưng tìm kiếm ở giữa chậm hơn. Những đối tượng này rất phù hợp cho việc áp dụng hàng đợi và phương pháp tìm kiếm theo chiều rộng (breadth-first tree search):
>>> from collections import deque
>>> d = deque(["task1", "task2", "task3"])
>>> d.append("task4")
>>> print("Handling", d.popleft())
Handling task1
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)
Một thư việc các công cụ được sử dụng để thay thế cho việc triển khai list ví dụ như module bisect
với chức năng kiểm soát danh sách đã sắp xếp:
>>> import bisect
>>> scores = [(100, 'perl'), (200, 'tcl'), (400, 'lua'), (500, 'python')]
>>> bisect.insort(scores, (300, 'ruby'))
>>> scores
[(100, 'perl'), (200, 'tcl'), (300, 'ruby'), (400, 'lua'), (500, 'python')]
Module heapq
cung cấp các chức năng cho việc triển khai dựa trên heaps (một cấu trúc dữ liệu dạng cây) trên các danh sách thông thường. Ngõ vào giá trị thấp nhất luôn luôn giữ ở vị trí không (zero). Điều này hữu dụng cho các ứng dụng truy cập một cách có chu kỳ phần tử nhỏ nhất nhưng không muốn chạy một thuật toán sắp xếp đầy đủ:
>>> from heapq import heapify, heappop, heappush
>>> data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0]
>>> heapify(data) # sắp xếp danh sách trong thứ tự của heap
>>> heappush(data, -5) # thêm một cổng mới
>>> [heappop(data) for i in range(3)] # dẫn ra 3 cổng nhỏ nhất
[-5, 0, 1]
Module decimal
đưa ra một kiểu dữ liệu thập phân Decimal
cho số học dấu chấm động thập phân. So với việc sử dụng dấu chấm động nhị phân được xây dựng sẵn float
, lớp này đặc biệt hữu ích cho
- các ứng dụng tài chính và mục đích sử dụng khác yêu cầu một con số thập phân đại diện chính xác,
- kiểm soát độ chính xác,
- kiểm soát việc làm tròn cho phù hợp hoặc những quy định yêu cầu,
- theo dấu những vị trí thập phân quan trọng, hoặc
- các ứng dụng mà người dùng trông đợi kết quả phù hợp với việc tính toán bằng tay.
Ví dụ, việc tính một khoản thuế 5% trên 70cent (100cent = 1$) cho một khoản phí điện thoại trả về các kết quả các nhau khi sử dụng dấu chấm động thập phân và dấu chấm động nhị phân. Sự khác biệt trở nên dễ thấy nếu kết quả được làm tròn đến cent gần nhất:
>>> from decimal import *
>>> round(Decimal('0.70') * Decimal('1.05'), 2)
Decimal('0.74')
>>> round(.70 * 1.05, 2)
0.73
Kết quả của Decimal
giữ một dấu 0, tự động inferring four place significance from multiplicands with two place significance. Decimal reproduces mathematics as done by hand and avoids issues that can arise when binary floating point cannot exactly represent decimal quantities.
Đại diện chính xác cho phép lớp Decimal
biểu thị các tính toán lấy dư(modulo) và các kiểm tra bằng mà điều này lại không phù hợp cho dấu chấm động nhị phân:
>>> Decimal('1.00') % Decimal('.10')
Decimal('0.00')
>>> 1.00 % 0.10
0.09999999999999995
>>> sum([Decimal('0.1')]*10) == Decimal('1.0')
True
>>> sum([0.1]*10) == 1.0
False
Module decimal
cung cấp số học đủ chính xác đến mức yêu cầu.
>>> getcontext().prec = 36
>>> Decimal(1) / Decimal(7)
Decimal('0.142857142857142857142857142857142857')