11. Brief Tour of the Standard Library — Part II标准库简介(2)¶
This second tour covers more advanced modules that support professional programming needs. 第二部分介绍了支持专业编程需求的更高级模块。These modules rarely occur in small scripts.这些模块很少出现在小脚本中。
11.1. Output Formatting输出格式化¶
The reprlib
module provides a version of repr()
customized for abbreviated displays of large or deeply nested containers:reprlib
模块提供了一个版本的repr()
,可为大型或深度嵌套容器的简短显示定制:
>>> import reprlib
>>> reprlib.repr(set('supercalifragilisticexpialidocious'))
"{'a', 'c', 'd', 'e', 'f', 'g', ...}"
The pprint
module offers more sophisticated control over printing both built-in and user defined objects in a way that is readable by the interpreter. pprint
模块以解释器可读的方式对打印内置和用户定义的对象提供更复杂的控制。When the result is longer than one line, the “pretty printer” adds line breaks and indentation to more clearly reveal data structure:当结果超过一行时,“漂亮打印机”会添加换行符和缩进,以更清楚地显示数据结构:
>>> import pprint
>>> t = [[[['black', 'cyan'], 'white', ['green', 'red']], [['magenta',
... 'yellow'], 'blue']]]
...
>>> pprint.pprint(t, width=30)
[[[['black', 'cyan'],
'white',
['green', 'red']],
[['magenta', 'yellow'],
'blue']]]
The textwrap
module formats paragraphs of text to fit a given screen width: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))
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.
The locale
module accesses a database of culture specific data formats. locale
模块访问特定于区域性的数据格式的数据库。The grouping attribute of locale’s format function provides a direct way of formatting numbers with group separators:locale的format函数的grouping属性提供了一种使用组分隔符格式化数字的直接方法:
>>> import locale
>>> locale.setlocale(locale.LC_ALL, 'English_United States.1252')
'English_United States.1252'
>>> conv = locale.localeconv() # get a mapping of conventions
>>> 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'
11.2. Templating模板¶
The string
module includes a versatile Template
class with a simplified syntax suitable for editing by end-users. string
模块包括一个多功能Template
类,该类具有适合最终用户编辑的简化语法。This allows users to customize their applications without having to alter the application.这允许用户定制自己的应用程序,而无需更改应用程序。
The format uses placeholder names formed by 该格式使用由$
with valid Python identifiers (alphanumeric characters and underscores). $
构成的占位符名和有效的Python标识符(字母数字字符和下划线)。Surrounding the placeholder with braces allows it to be followed by more alphanumeric letters with no intervening spaces. 在占位符周围加上大括号,可以让占位符后面有更多的字母数字字母,中间没有空格。Writing 写入$$
creates a single escaped $
:$$
将创建一个转义$
:
>>> 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.'
The 当字典或关键字参数中未提供占位符时,substitute()
method raises a KeyError
when a placeholder is not supplied in a dictionary or a keyword argument. substitute()
方法会引发KeyError
。For mail-merge style applications, user supplied data may be incomplete and the 对于邮件合并样式的应用程序,用户提供的数据可能不完整,而safe_substitute()
method may be more appropriate — it will leave placeholders unchanged if data is missing:safe_substitute()
方法可能更合适——如果缺少数据,它将保持占位符不变:
>>> 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.'
Template subclasses can specify a custom delimiter. 模板子类可以指定自定义分隔符。For example, a batch renaming utility for a photo browser may elect to use percent signs for placeholders such as the current date, image sequence number, or file format:例如,照片浏览器的批量重命名实用程序可能会选择使用百分比符号作为占位符,例如当前日期、图像序列号或文件格式:
>>> 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
Another application for templating is separating program logic from the details of multiple output formats. 模板的另一个应用是将程序逻辑与多种输出格式的细节分离。This makes it possible to substitute custom templates for XML files, plain text reports, and HTML web reports.这使得用自定义模板替换XML文件、纯文本报告和HTML web报告成为可能。
11.3. Working with Binary Data Record Layouts使用二进制数据记录布局¶
The struct
module provides pack()
and unpack()
functions for working with variable length binary record formats. struct
模块提供pack()
和unpack()
函数,用于处理可变长度的二进制记录格式。The following example shows how to loop through header information in a ZIP file without using the 下面的示例演示如何在不使用zipfile
module. zipfile
模块的情况下循环查看ZIP文件中的头信息。Pack codes 包装代码"H"
and "I"
represent two and four byte unsigned numbers respectively. "H"
和"I"
分别代表两个字节和四个字节的无符号数字。The "<"
indicates that they are standard size and in little-endian byte order:"<"
表示它们是标准大小,以小尾端字节顺序排列:
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
11.4. Multi-threading多线程¶
Threading is a technique for decoupling tasks which are not sequentially dependent. 线程是一种解耦任务的技术,这些任务不是顺序依赖的。Threads can be used to improve the responsiveness of applications that accept user input while other tasks run in the background. 线程可以用来提高在后台运行其他任务时接受用户输入的应用程序的响应能力。A related use case is running I/O in parallel with computations in another thread.一个相关的用例是在另一个线程中并行运行I/O和计算。
The following code shows how the high level 以下代码显示了在主程序继续运行时,高级threading
module can run tasks in background while the main program continues to run: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.')
The principal challenge of multi-threaded applications is coordinating threads that share data or other resources. 多线程应用程序的主要挑战是协调共享数据或其他资源的线程。To that end, the threading module provides a number of synchronization primitives including locks, events, condition variables, and semaphores.为此,线程模块提供了许多同步原语,包括锁、事件、条件变量和信号量。
While those tools are powerful, minor design errors can result in problems that are difficult to reproduce. 虽然这些工具功能强大,但微小的设计错误可能会导致难以重现的问题。So, the preferred approach to task coordination is to concentrate all access to a resource in a single thread and then use the 因此,任务协调的首选方法是将对资源的所有访问集中在单个线程中,然后使用queue
module to feed that thread with requests from other threads. queue
模块向该线程提供来自其他线程的请求。Applications using 使用Queue
objects for inter-thread communication and coordination are easier to design, more readable, and more reliable.Queue
对象进行线程间通信和协调的应用程序更易于设计,可读性更强,可靠性更高。
11.5. Logging¶
The logging
module offers a full featured and flexible logging system. logging
模块提供了一个功能齐全、灵活的日志系统。At its simplest, log messages are sent to a file or to 最简单的情况是,日志消息被发送到文件或sys.stderr
: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')
This produces the following output:这将产生以下输出:
WARNING:root:Warning:config file server.conf not found
ERROR:root:Error occurred
CRITICAL:root:Critical error -- shutting down
By default, informational and debugging messages are suppressed and the output is sent to standard error. 默认情况下,信息和调试消息被抑制,输出被发送到标准错误。Other output options include routing messages through email, datagrams, sockets, or to an HTTP Server. 其他输出选项包括通过电子邮件、数据报、套接字或HTTP服务器路由消息。New filters can select different routing based on message priority: 新筛选器可以根据消息优先级选择不同的路由:DEBUG
, INFO
, WARNING
, ERROR
, and CRITICAL
.DEBUG
、INFO
、WARNING
、ERROR
和CRITICAL
。
The logging system can be configured directly from Python or can be loaded from a user editable configuration file for customized logging without altering the application.日志系统可以直接从Python配置,也可以从用户可编辑的配置文件加载,以便在不改变应用程序的情况下进行自定义日志记录。
11.6. Weak References弱引用¶
Python does automatic memory management (reference counting for most objects and garbage collection to eliminate cycles). Python进行自动内存管理(对大多数对象进行引用计数,并进行垃圾收集以消除循环)。The memory is freed shortly after the last reference to it has been eliminated.内存在最后一次引用被删除后不久被释放。
This approach works fine for most applications but occasionally there is a need to track objects only as long as they are being used by something else. 这种方法适用于大多数应用程序,但偶尔需要跟踪对象,只要它们被其他应用程序使用。Unfortunately, just tracking them creates a reference that makes them permanent. 不幸的是,仅仅跟踪它们就产生了一个永久性的引用。The weakref模块提供了无需创建引用即可跟踪对象的工具。weakref
module provides tools for tracking objects without creating a reference. When the object is no longer needed, it is automatically removed from a weakref table and a callback is triggered for weakref objects. 当不再需要该对象时,它会自动从weakref
表中删除,并为weakref
对象触发回调。Typical applications include caching objects that are expensive to create:典型的应用程序包括缓存创建成本高昂的对象:
>>> 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
10
>>> del a # remove the one reference
>>> gc.collect() # run garbage collection right away
0
>>> d['primary'] # entry was automatically removed
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
d['primary'] # entry was automatically removed
File "C:/python310/lib/weakref.py", line 46, in __getitem__
o = self.data[key]()
KeyError: 'primary'
11.7. Tools for Working with Lists用于处理列表的工具¶
Many data structure needs can be met with the built-in list type. 内置列表类型可以满足许多数据结构需求。However, sometimes there is a need for alternative implementations with different performance trade-offs.然而,有时需要不同性能权衡的替代实现。
The array
module provides an array()
object that is like a list that stores only homogeneous data and stores it more compactly. array
模块提供了一个array()
对象,它类似于一个列表,只存储同质数据,并将其存储得更紧凑。The following example shows an array of numbers stored as two byte unsigned binary numbers (typecode 下面的示例显示了一个存储为两字节无符号二进制数(类型代码"H"
) rather than the usual 16 bytes per entry for regular lists of Python int objects:"H"
)的数字数组,而不是Python int对象常规列表中通常每个条目16字节的数字:
>>> from array import array
>>> a = array('H', [4000, 10, 700, 22222])
>>> sum(a)
26932
>>> a[1:3]
array('H', [10, 700])
The collections
module provides a deque()
object that is like a list with faster appends and pops from the left side but slower lookups in the middle. collections
模块提供了一个deque()
对象,该对象类似于一个列表,左侧的附加和弹出速度更快,但中间的查找速度较慢。These objects are well suited for implementing queues and breadth first tree searches:这些对象非常适合实现队列和广度优先树搜索:
>>> 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)
In addition to alternative list implementations, the library also offers other tools such as the 除了可选的列表实现之外,该库还提供了其他工具,如bisect
module with functions for manipulating sorted lists:bisect
模块,该模块具有操作已排序列表的功能:
>>> 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')]
The heapq
module provides functions for implementing heaps based on regular lists. heapq
模块提供了基于常规列表实现堆的功能。The lowest valued entry is always kept at position zero. 值最低的条目始终保持在零位。This is useful for applications which repeatedly access the smallest element but do not want to run a full list sort:这对于重复访问最小元素但不希望运行完整列表排序的应用程序非常有用:
>>> 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
[-5, 0, 1]
11.8. Decimal Floating Point Arithmetic十进制浮点运算¶
The decimal模块为十进制浮点运算提供十进制数据类型。decimal
module offers a Decimal
datatype for decimal floating point arithmetic. Compared to the built-in 与二进制浮点的内置float
implementation of binary floating point, the class is especially helpful forfloat
实现相比,该类对
financial applications and other uses which require exact decimal representation,金融应用和其他需要精确十进制表示的用途,control over precision,控制精度,control over rounding to meet legal or regulatory requirements,控制舍入以满足法律或监管要求,tracking of significant decimal places, or跟踪有效小数位数,或applications where the user expects the results to match calculations done by hand.用户希望结果与手工计算相匹配的应用程序。
For example, calculating a 5% tax on a 70 cent phone charge gives different results in decimal floating point and binary floating point. 例如,对70美分的电话费计算5%的税费会得到十进制浮点和二进制浮点的不同结果。The difference becomes significant if the results are rounded to the nearest cent:如果将结果四舍五入至最接近的百分比,则差异变得显著:
>>> from decimal import *
>>> round(Decimal('0.70') * Decimal('1.05'), 2)
Decimal('0.74')
>>> round(.70 * 1.05, 2)
0.73
The Decimal
result keeps a trailing zero, automatically inferring four place significance from multiplicands with two place significance. Decimal
结果保留一个尾随的零,从具有两位意义的被乘数中自动推断出四位意义。Decimal reproduces mathematics as done by hand and avoids issues that can arise when binary floating point cannot exactly represent decimal quantities.Decimal复制了手工完成的数学,避免了二进制浮点不能准确表示十进制量时可能出现的问题。
Exact representation enables the 精确表示使Decimal
class to perform modulo calculations and equality tests that are unsuitable for binary floating point:Decimal
类能够执行不适用于二进制浮点的模计算和等式测试:
>>> 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
The decimal
module provides arithmetic with as much precision as needed:decimal
模块提供了所需精度的算术:
>>> getcontext().prec = 36
>>> Decimal(1) / Decimal(7)
Decimal('0.142857142857142857142857142857142857')