主题模式
Python 进阶工程实战:从语法精通到架构设计
Python 入门容易,但精通不易。装饰器、生成器、元编程、并发编程、类型系统、性能优化——这些才是区分 Python 新手和老手的分水岭。本文面向有 Python 基础的读者,深入讲解进阶特性与工程实践,帮助你从"会用"到"用好"。
本文由小虾子 撰写
装饰器:函数的超级英雄
装饰器基础
python
# 装饰器:接收函数,返回新函数
def log_calls(func):
def wrapper(*args, **kwargs):
print(f"调用 {func.__name__},参数:{args}, {kwargs}")
result = func(*args, **kwargs)
print(f"{func.__name__} 返回:{result}")
return result
return wrapper
@log_calls
def add(a, b):
return a + b
add(1, 2)
# 调用 add,参数:(1, 2), {}
# add 返回:3带参数的装饰器
python
# 三层嵌套:外层控制装饰器行为
def retry(max_attempts=3, delay=1):
def decorator(func):
def wrapper(*args, **kwargs):
import time
last_exception = None
for attempt in range(max_attempts):
try:
return func(*args, **kwargs)
except Exception as e:
last_exception = e
if attempt < max_attempts - 1:
time.sleep(delay)
print(f"重试 {attempt + 1}/{max_attempts}...")
raise last_exception
return wrapper
return decorator
@retry(max_attempts=5, delay=2)
def fetch_data(url):
# 模拟网络请求,可能失败
import random
if random.random() < 0.7:
raise ConnectionError("网络错误")
return "数据"
fetch_data("https://api.example.com")类装饰器与 functools
python
import functools
import time
# 类装饰器:装饰器本身是类
class RateLimiter:
def __init__(self, max_calls: int, period: float):
self.max_calls = max_calls
self.period = period
self.calls: list[float] = []
def __call__(self, func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
now = time.time()
# 清理过期的记录
self.calls = [t for t in self.calls if now - t < self.period]
if len(self.calls) >= self.max_calls:
wait = self.period - (now - self.calls[0])
raise RuntimeError(f"触发速率限制,需等待 {wait:.1f} 秒")
self.calls.append(now)
return func(*args, **kwargs)
return wrapper
@RateLimiter(max_calls=3, period=60)
def send_sms(phone: str, message: str):
print(f"发送短信到 {phone}:{message}")
return True
# functools.wraps:保留原函数元信息
def my_decorator(func):
@functools.wraps(func) # 保留函数名、文档字符串、类型注解
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@my_decorator
def documented_function(x: int) -> int:
"""这是函数的文档字符串"""
return x * 2
print(documented_function.__name__) # documented_function(而非 wrapper)
print(documented_function.__doc__) # 这是函数的文档字符串生成器与迭代器:惰性计算的艺术
生成器基础
python
# 生成器:惰性迭代器,用完即弃
def count_up_to(n):
i = 1
while i <= n:
yield i # yield 暂停函数,返回值
i += 1
gen = count_up_to(5)
print(next(gen)) # 1
print(next(gen)) # 2
print(list(gen)) # [3, 4, 5](剩余部分)
# 生成器表达式(内存友好)
squares = (x**2 for x in range(10**8)) # 不占用大内存!
for sq in squares:
if sq > 100:
break
print(sq)
# 斐波那契生成器
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
fib = fibonacci()
print([next(fib) for _ in range(10)]) # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]itertools:生成器的瑞士军刀
python
import itertools
# 无限迭代器
count = itertools.count(1) # 1, 2, 3, ...(无限)
cycle = itertools.cycle([1, 2, 3]) # 1, 2, 3, 1, 2, 3, ...(无限)
repeat = itertools.repeat("x", 3) # x, x, x(重复 n 次)
# 有限迭代器
islice = itertools.islice(count, 10) # 取前 10 个
takewhile = itertools.takewhile(lambda x: x < 5, count) # 条件为 False 时停止
dropwhile = itertools.dropwhile(lambda x: x < 3, [1,2,3,4,5]) # 条件为 True 时跳过
filterfalse = itertools.filterfalse(bool, [0, 1, False, 2, ""]) # 保留 False 的
# 排列组合
perms = itertools.permutations([1, 2, 3], 2) # (1,2), (1,3), (2,1), (2,3), (3,1), (3,2)
combs = itertools.combinations([1, 2, 3], 2) # (1,2), (1,3), (2,3)
combs_with_replacement = itertools.combinations_with_replacement([1, 2, 3], 2) # (1,1), (1,2), ...
# 链式操作
chain = itertools.chain([1, 2], [3, 4], [5]) # 1, 2, 3, 4, 5
zip_longest = itertools.zip_longest([1, 2, 3], ['a', 'b'], fillvalue=None) # (1,'a'), (2,'b'), (3,None)
# 分组
groups = itertools.groupby(sorted(["aa", "ab", "bb", "bc"]), key=lambda x: x[0])
# ('a', ['aa', 'ab']), ('b', ['bb', 'bc'])数据管道:生成器的工程价值
python
# 大文件处理:逐行读取,不占用大量内存
def process_large_log(filepath: str):
with open(filepath) as f:
for line in f: # 逐行读取,内存友好
parts = line.strip().split()
if len(parts) >= 3:
yield {
"timestamp": parts[0],
"level": parts[1],
"message": " ".join(parts[2:]),
}
def filter_errors(lines):
for line in lines:
if line["level"] == "ERROR":
yield line
def enrich(lines):
for line in lines:
line["enriched"] = True
yield line
# 惰性链式处理:100GB 日志文件也只需几 MB 内存
error_lines = enrich(filter_errors(process_large_log("app.log")))
for error in itertools.islice(error_lines, 100): # 只取前 100 条
print(error)上下文管理器:资源的守护者
类实现上下文管理器
python
class DatabaseConnection:
def __init__(self, connection_string: str):
self.conn_string = connection_string
self.conn = None
def __enter__(self):
print(f"连接数据库:{self.conn_string}")
self.conn = {"status": "connected"}
return self.conn
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type:
print(f"发生异常:{exc_type.__name__}:{exc_val}")
print("关闭数据库连接")
self.conn = None
return False # 不吞异常
with DatabaseConnection("postgresql://localhost/mydb") as conn:
print(f"执行查询:{conn}")
# conn["status"] = "querying"
print("继续执行...") # __exit__ 已执行
# 异常情况
with DatabaseConnection("postgresql://localhost/mydb") as conn:
raise ValueError("查询失败")
# 输出:发生异常:ValueError:查询失败
# 输出:关闭数据库连接
# 异常继续向上传播@contextmanager 装饰器实现
python
from contextlib import contextmanager
@contextmanager
def open_file(path: str, mode: str = "r"):
"""比类实现更简洁的上下文管理器"""
f = open(path, mode)
try:
yield f
finally:
f.close()
# 嵌套上下文
@contextmanager
def transaction(conn):
conn.begin()
try:
yield conn
conn.commit()
except Exception:
conn.rollback()
raise
# 组合多个上下文管理器
from contextlib import ExitStack
def process_files(filepaths: list[str]):
with ExitStack() as stack:
files = [stack.enter_context(open_file(fp)) for fp in filepaths]
# 所有文件同时打开,同时关闭
content = [f.read() for f in files]
return content元编程:代码的代码
动态属性与 getattr
python
class LazyObject:
"""延迟加载对象(按需初始化)"""
def __init__(self, factory):
self._factory = factory
self._cache = {}
def __getattr__(self, name):
if name.startswith("_"):
return super().__getattribute__(name)
if name not in self._cache:
print(f"首次访问 {name},执行初始化...")
self._cache[name] = self._factory()
return self._cache[name]
db = LazyObject(lambda: {"tables": ["users", "orders"]})
print(db.tables) # 首次访问,打印 "首次访问 tables..."
print(db.tables) # 第二次,直接返回缓存
# 动态创建类
def create_model(table_name: str, fields: dict):
"""根据表结构动态创建 ORM 模型"""
class Model:
def __init__(self, **kwargs):
for k, v in fields.items():
setattr(self, k, kwargs.get(k, None))
def __repr__(self):
return f"<{table_name} {self.__dict__}>"
@classmethod
def columns(cls):
return list(fields.keys())
Model.__name__ = table_name.capitalize()
return Model
User = create_model("users", {
"id": int,
"name": str,
"email": str,
"age": int,
})
user = User(id=1, name="小虾子", email="xia@xia.com")
print(User.columns()) # ['id', 'name', 'email', 'age']元类(Metaclass)
python
# 元类:类的类,控制类的创建过程
class ModelMeta(type):
"""自动注册 Model 子类"""
registry = {}
def __new__(mcs, name, bases, namespace):
cls = super().__new__(mcs, name, bases, namespace)
if name != "Model": # 排除基类本身
mcs.registry[name] = cls
return cls
class Model(metaclass=ModelMeta):
"""所有数据模型的基类"""
def save(self):
table = self.__class__.__name__.lower()
columns = [k for k in self.__dict__ if not k.startswith("_")]
values = [getattr(self, k) for k in columns]
print(f"INSERT INTO {table} ({columns}) VALUES ({values})")
class User(Model):
def __init__(self, name: str, email: str):
self.name = name
self.email = email
class Product(Model):
def __init__(self, name: str, price: float):
self.name = name
self.price = price
# 自动注册!
user = User("小虾子", "xia@xia.com")
product = Product("键盘", 299.0)
print(ModelMeta.registry) # {'User': <class '__main__.User'>, 'Product': <class '__main__.Product'>}
# ORM 自动发现所有模型
for model_name, model_cls in ModelMeta.registry.items():
print(f"发现模型:{model_name}")装饰器元编程
python
# 类装饰器:批量注册路由
def register_routes(prefix: str = ""):
def decorator(cls):
cls._routes = {}
for name in dir(cls):
if not name.startswith("_"):
method = getattr(cls, name)
if callable(method):
route = getattr(method, "_route", None)
if route:
cls._routes[route] = method
return cls
return decorator
def route(path: str, methods: list[str] = ["GET"]):
def decorator(func):
func._route = (path, tuple(methods))
return func
return decorator
@register_routes("/api/users")
class UserAPI:
@route("/users", ["GET"])
def list_users(self):
return ["user1", "user2"]
@route("/users/<id>", ["GET"])
def get_user(self, id: int):
return {"id": id, "name": "小虾子"}
# 自动发现路由
for (path, methods), handler in UserAPI._routes.items():
print(f"{methods} {path} -> {handler.__name__}")
# ('GET',) /users -> list_users
# ('GET',) /users/<id> -> get_user类型系统进阶
Protocol:结构化子类型(静态鸭子类型)
python
# 传统方式:显式继承
class PDFReader:
def read(self, path: str) -> bytes:
...
class ImageReader:
def read(self, path: str) -> bytes:
...
# 问题:PDFReader 和 ImageReader 没有共同基类
def process_file(reader: PDFReader | ImageReader, path: str):
...
# Protocol:定义结构化接口(不需继承)
from typing import Protocol, runtime_checkable
@runtime_checkable
class FileReader(Protocol):
def read(self, path: str) -> bytes: ...
# PDFReader 和 ImageReader 只要有 read(path: str) -> bytes 方法
# 静态检查器就认为它们实现了 FileReader
def process_file(reader: FileReader, path: str) -> bytes:
return reader.read(path)
# runtime_checkable:运行时也可以检查
print(isinstance(pdf_reader, FileReader)) # True泛型(Generic Types)
python
from typing import TypeVar, Generic, Union
T = TypeVar("T")
K = TypeVar("K")
V = TypeVar("V")
class Stack(Generic[T]):
def __init__(self):
self._items: list[T] = []
def push(self, item: T):
self._items.append(item)
def pop(self) -> T:
if not self._items:
raise IndexError("Stack is empty")
return self._items.pop()
def peek(self) -> T:
return self._items[-1]
# 约束类型变量
def first(seq: list[T]) -> T:
return seq[0]
# 泛型字典
def merge_dicts(d1: dict[K, V], d2: dict[K, V]) -> dict[K, V]:
result = d1.copy()
result.update(d2)
return result
# TypeVar 约束
import numbers
Number = TypeVar("Number", bound=numbers.Real) # 必须是 Real 的子类
def average(nums: list[Number]) -> float:
return sum(nums) / len(nums)
average([1, 2, 3]) # 正确
average([1.5, 2.5]) # 正确
average(["a", "b"]) # 错误 类型错误NewType 与类型别名
python
from typing import NewType
# NewType:编译期区分语义相同的类型
UserId = NewType("UserId", int)
OrderId = NewType("OrderId", int)
def get_user(user_id: UserId) -> dict:
return {"id": int(user_id), "name": "小虾子"}
def get_order(order_id: OrderId) -> dict:
return {"id": int(order_id), "total": 99.0}
uid = UserId(1)
oid = OrderId(1)
get_user(oid) # 错误 类型检查器报错:期望 UserId,实际是 OrderId
get_user(UserId(oid)) # 需要显式转换
# 类型别名
from typing import Callable
Predicate = Callable[[int], bool]
Reducer = Callable[[int, int], int]
# Literal 类型
from typing import Literal
Mode = Literal["r", "w", "a"]
def open_file(path: str, mode: Mode):
...
open_file("test.txt", "r") # 正确
open_file("test.txt", "x") # 错误 类型检查器报错并发编程
asyncio:协程异步 I/O
python
import asyncio
import aiohttp
# async/await 语法
async def fetch(url: str) -> str:
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.text()
# 并发执行多个请求
async def fetch_all(urls: list[str]):
tasks = [fetch(url) for url in urls]
results = await asyncio.gather(*tasks) # 并发执行!
return results
# 实际执行
async def main():
urls = [
"https://api.github.com/users/ljt1024",
"https://api.github.com/users/torvalds",
"https://api.github.com/users/",
]
results = await fetch_all(urls)
for url, result in zip(urls, results):
print(f"{url}: {len(result)} bytes")
asyncio.run(main())
# asyncio 队列(生产者-消费者)
async def producer(queue: asyncio.Queue):
for i in range(10):
await queue.put(i)
await asyncio.sleep(0.1)
await queue.put(None) # 发送终止信号
async def consumer(queue: asyncio.Queue):
while True:
item = await queue.get()
if item is None:
break
print(f"消费:{item}")
async def main():
queue = asyncio.Queue()
await asyncio.gather(
producer(queue),
consumer(queue),
)threading 与 multiprocessing
python
# threading:I/O 密集型(网络请求、文件读写)
import threading
import time
def download(url: str, results: dict, index: int):
time.sleep(1) # 模拟下载
results[index] = f"完成:{url}"
results = [None] * 3
threads = [
threading.Thread(target=download, args=(f"url_{i}", results, i))
for i in range(3)
]
for t in threads:
t.start()
for t in threads:
t.join()
print(results)
# multiprocessing:CPU 密集型(计算)
import multiprocessing
from math import sqrt
def is_prime(n: int) -> bool:
if n < 2:
return False
for i in range(2, int(sqrt(n)) + 1):
if n % i == 0:
return False
return True
def count_primes_in_range(start: int, end: int) -> int:
return sum(is_prime(n) for n in range(start, end))
if __name__ == "__main__":
with multiprocessing.Pool(4) as pool:
ranges = [(0, 250000), (250000, 500000),
(500000, 750000), (750000, 1000000)]
results = pool.starmap(count_primes_in_range, ranges)
print(f"质数总数:{sum(results)}")concurrent.futures:高级并发接口
python
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
# 线程池(I/O 密集型)
with ThreadPoolExecutor(max_workers=10) as executor:
futures = [executor.submit(requests.get, url) for url in urls]
for future in futures:
response = future.result() # 获取结果(阻塞)
print(response.status_code)
# 进程池(CPU 密集型)
def expensive_computation(n: int) -> int:
return sum(i**2 for i in range(n))
with ProcessPoolExecutor(max_workers=4) as executor:
results = list(executor.map(expensive_computation, [10**6] * 8))
# asyncio + concurrent.futures:混合使用
def blocking_io():
time.sleep(1)
return "完成"
async def main():
loop = asyncio.get_event_loop()
# 在线程池中运行阻塞代码
result = await loop.run_in_executor(None, blocking_io)
print(result)性能优化
profiling 与 benchmark
python
import time
import cProfile
import pstats
from io import StringIO
# 简单计时
def time_it(func, *args, n=100):
start = time.perf_counter()
for _ in range(n):
func(*args)
elapsed = (time.perf_counter() - start) / n
print(f"{func.__name__}:{elapsed * 1000:.3f} ms/次(平均{n}次)")
# cProfile:性能分析
cProfile.run("sum(range(10**6))", "profile.stats")
p = pstats.Stats("profile.stats")
p.sort_stats("cumulative").print_stats(10) # 累计时间前10
# memory_profiler
# pip install memory_profiler
# @profile
def memory_heavy():
data = [i**2 for i in range(10**6)]
return data
# line_profiler(逐行分析)
# pip install line_profiler
# kernprof -l -v script.py
# @profile
def compute():
result = 0
for i in range(10**6):
result += i * i
return result常见性能陷阱与优化
python
# 错误 陷阱 1:字符串拼接(字符串不可变,每次+都创建新字符串)
s = ""
for i in range(10000):
s += str(i) # 创建 10000 个字符串对象!
# 正确 优化:用 list + join
parts = []
for i in range(10000):
parts.append(str(i))
s = "".join(parts) # 一次拼接
# 错误 陷阱 2:列表 contains 检查
if item in large_list: # O(n) 线性查找
...
# 正确 优化:用 set
large_set = set(large_list) # O(1) 查找
if item in large_set:
...
# 错误 陷阱 3:重复计算
for i in range(n):
for j in range(n):
compute() # n^2 次计算
# 正确 优化:缓存重复计算(lru_cache)
from functools import lru_cache
@lru_cache(maxsize=None)
def fibonacci(n: int) -> int:
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2) # 缓存后 O(n) 而非 O(2^n)
# 错误 陷阱 4:创建不必要的中间列表
squares = [x**2 for x in range(10**6)] # 一次性创建 10**6 个元素
# 正确 优化:生成器(惰性)
squares = (x**2 for x in range(10**6)) # 惰性,不占内存Cython 与 PyPy
python
# Cython:编译 Python 为 C,性能提升 10-100x
# hello.pyx
def compute_primes(int n):
cdef int count = 0
cdef int i, j
cdef bint is_prime
result = []
for i in range(2, n):
is_prime = True
for j in range(2, int(i**0.5) + 1):
if i % j == 0:
is_prime = False
break
if is_prime:
count += 1
return count
# setup.py
# from setuptools import setup
# from Cython.Build import cythonize
# setup(ext_modules=cythonize("hello.pyx"))
# PyPy:JIT 编译器,数值计算性能大幅提升
# python -m pypy script.py
# 适合长时间运行的程序,JIT 预热后加速明显架构设计模式
工厂模式与依赖注入
python
from abc import ABC, abstractmethod
# 抽象基类
class Logger(ABC):
@abstractmethod
def log(self, message: str): ...
class FileLogger(Logger):
def __init__(self, filepath: str):
self.filepath = filepath
def log(self, message: str):
with open(self.filepath, "a") as f:
f.write(message + "\n")
class ConsoleLogger(Logger):
def log(self, message: str):
print(message)
# 工厂函数
def create_logger(kind: str, **kwargs) -> Logger:
loggers = {
"file": FileLogger,
"console": ConsoleLogger,
}
return loggers[kind](**kwargs)
# 依赖注入(更 Pythonic)
class UserService:
def __init__(self, logger: Logger):
self.logger = logger
def create_user(self, name: str):
self.logger.log(f"创建用户:{name}")
...
# 使用
logger = create_logger("file", filepath="/var/log/app.log")
service = UserService(logger)观察者模式
python
class EventEmitter:
def __init__(self):
self._listeners: dict[str, list[callable]] = {}
def on(self, event: str, callback: callable):
if event not in self._listeners:
self._listeners[event] = []
self._listeners[event].append(callback)
return self # 支持链式调用
def off(self, event: str, callback: callable):
if event in self._listeners:
self._listeners[event].remove(callback)
return self
def emit(self, event: str, *args, **kwargs):
if event in self._listeners:
for callback in self._listeners[event]:
callback(*args, **kwargs)
return self
# 使用
emitter = EventEmitter()
def on_click(data):
print(f"点击:{data}")
emitter.on("click", on_click)
emitter.on("click", lambda d: print(f"记录:{d}"))
emitter.emit("click", {"x": 100, "y": 200})
# 点击:{'x': 100, 'y': 200}
# 记录:{'x': 100, 'y': 200}总结
Python 进阶技能地图:
─────────────────────────────────
装饰器:
正确 参数化装饰器、类装饰器、functools.wraps
正确 常用内置装饰器:@property, @classmethod, @staticmethod
生成器与迭代器:
正确 yield、生成器表达式、itertools 组合使用
正确 大文件惰性处理管道
上下文管理器:
正确 __enter__/__exit__、@contextmanager
正确 ExitStack、资源组合管理
元编程:
正确 __getattr__、动态类创建、装饰器元编程
正确 元类(ModelMeta、ORM 自动注册)
类型系统:
正确 Protocol(结构化子类型)、泛型、NewType
正确 TypeGuard、Literal、类型守卫
并发编程:
正确 asyncio + await、协程、队列
正确 threading(I/O)、multiprocessing(CPU)
正确 concurrent.futures
性能优化:
正确 cProfile 性能分析、lru_cache 缓存
正确 避免字符串拼接陷阱、生成器替代列表
正确 Cython、PyPy工程实践检查清单:
─────────────────────────────────
□ 类型注解:所有公开函数和类都加上类型注解
□ 文档字符串:每个模块、类、函数写 docstring
□ 异常处理:关键操作使用 try-except,不吞异常
□ 资源管理:文件/连接用 with 语句或上下文管理器
□ 单元测试:pytest 覆盖核心逻辑
□ 依赖管理:requirements.txt 或 pyproject.toml + uv
□ 代码格式:ruff / black + isort
□ 性能意识:I/O 密集用 asyncio,CPU 密集用 multiprocessingPython 的深度在于"用好标准库、用对场景"——装饰器解决横切关注点、生成器解决内存效率、元编程解决框架构建、并发解决性能问题。掌握这些,你就从"会用 Python"进化到了"精通 Python"
本文由小虾子 撰写