11. 标准库简介 II
美化输出、Template、struct、线程与队列、logging、weakref、collections 工具箱、decimal——深入「第二轮」常用库。
11.1 格式化与可读输出
reprlib
import reprlib
print(reprlib.repr(set("supercalifragilisticexpialidocious"))) # {'a', 'c', 'd', 'e', 'f', 'g', ...}pprint
from pprint import pprint
pprint({"key": {"nested": [{"id": i} for i in range(3)]}}) # {'key': {'nested': [{'id': 0}, {'id': 1}, {'id': 2}]}}(更大时会多行缩进)textwrap
import textwrap
s = "very long line " * 10
print(textwrap.fill(s, width=40)) # very long line ...(多行;每行宽度不超过 40)locale
了解即可;服务端更推荐显式格式或只做 UTC + ISO。
11.2 模板:string.Template
当占位符与 str.format 的花括号/自定义 DSL 冲突时用:
from string import Template
sql_like = Template("SELECT $$literal, ${col} FROM t WHERE id = $id")
print(sql_like.safe_substitute(col="name", id="42")) # SELECT $literal, name FROM t WHERE id = 42(缺键时未提供的占位符原样保留)11.3 二进制:struct
import struct
packed = struct.pack("=IH", 42, 1024) # = 表示「本机字节序但禁止填充」
value_u16, value_u32 = struct.unpack("=IH", packed)
print(value_u16, value_u32) # 42 102411.4 线程与队列
import queue
import threading
q: queue.Queue[int] = queue.Queue()
def worker() -> None:
while True:
item = q.get()
if item is None:
q.task_done()
break
try:
print("process", item) # process 1(对每个非 None 任务一行)
finally:
q.task_done()
t = threading.Thread(target=worker, daemon=True)
t.start()
q.put(1)
q.put(None)
q.join()
t.join()I/O 密集可用线程;CPU 密集需要 multiprocessing(或别语言运行时)。
11.5 日志:logging
import logging
logging.basicConfig(level=logging.INFO, format="%(levelname)s %(name)s: %(message)s")
log = logging.getLogger(__name__)
log.info("started")
try:
1 / 0
except ZeroDivisionError:
log.exception("boom") # ERROR + 栈库代码只 getLogger,由应用配置 handler(文件、轮转、JSON 等)。
11.6 弱引用:weakref
实现「缓存不妨碍 GC」或注册表时才会碰到;日常不必手写。
import weakref
class Big:
pass
cache: weakref.WeakValueDictionary[str, Big] = weakref.WeakValueDictionary()
obj = Big()
cache["k"] = obj
del obj
print(list(cache.keys())) # [](弱引用目标已回收;若 GC 尚未运行则可能短暂仍有 'k')11.7 collections 工具箱
| 工具 | 场景 |
|---|---|
deque | 双端 O(1) |
Counter | 频次 |
defaultdict | 缺省工厂 |
namedtuple / dataclass | 记录体 |
from collections import Counter, deque
print(Counter("abracadabra").most_common(3)) # [('a', 5), ('b', 2), ('r', 2)]
dq = deque(maxlen=3)
for i in range(5):
dq.append(i)
print(list(dq)) # [2, 3, 4](maxlen=3,只保留最后 3 个)11.8 精确十进制:decimal
from decimal import Decimal, ROUND_HALF_UP, getcontext
getcontext().prec = 6
x = Decimal("2.675")
print(x.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)) # 2.6811.9 速记
pprint/reprlib:对付巨大嵌套结构。logging:替代到处print。- 钱:
Decimal;数组算子:numpy(第三方)。