1. Python数据结构核心概念解析
作为一名从Python 2.7时代就开始使用Python的老程序员,我见证了Python数据结构在不同版本中的演进。数据结构是编程的基石,掌握它们的特点和使用场景,能让你写出更高效、更优雅的代码。今天,我将结合自己多年的实战经验,带你深入理解Python中最常用的几种数据结构。
1.1 列表(List)的灵活性与陷阱
列表是Python中最常用的数据结构之一,它的可变性(Mutable)让它成为处理动态数据的首选。但正是这种灵活性,也带来了不少初学者容易踩的坑。
列表的常用方法中,有几个特别需要注意的行为特征:
append()和extend()的区别:append()会将整个参数作为一个元素添加,而extend()则会展开可迭代对象中的元素sort()和sorted()的不同:前者原地排序并返回None,后者返回新列表- 切片操作的内存行为:浅拷贝意味着嵌套结构的修改会影响原列表
重要提示:当处理大型列表时,频繁的
insert(0, x)或pop(0)操作会导致性能问题,因为需要移动所有后续元素。这是很多新手在实现队列时容易忽视的性能陷阱。
1.1.1 列表作为栈的正确使用方式
栈(LIFO)是列表最自然的应用场景之一。Python列表的append()和pop()方法都是O(1)时间复杂度,非常适合栈操作。
python复制# 正确的栈实现
stack = []
stack.append('document1') # 入栈
stack.append('document2')
last_in = stack.pop() # 出栈,得到'document2'
1.1.2 为什么列表不适合做队列
虽然可以用append()和pop(0)模拟队列(FIFO),但pop(0)的O(n)时间复杂度在大数据量时会导致严重性能问题。我在处理一个百万级任务队列时,就曾因此导致程序卡顿。
python复制# 不推荐的队列实现(性能差)
queue = []
queue.append('task1')
queue.append('task2')
first_in = queue.pop(0) # 时间复杂度O(n)
1.2 元组(Tuple)的不可变优势
元组是不可变序列,这一特性让它成为安全的数据容器。我经常在以下场景使用元组:
- 函数返回多个值时
- 作为字典的键(因为不可变)
- 定义常量集合
python复制# 典型的多返回值用法
def get_user_info(user_id):
# ...获取数据逻辑
return (user_name, user_email, join_date) # 使用元组包装多个返回值
# 作为字典键
locations = {
(35.6895, 139.6917): "Tokyo",
(40.7128, -74.0060): "New York"
}
经验分享:单元素元组必须加逗号,如
(1,),否则Python会将其视为普通括号表达式。这是我早期常犯的错误之一。
2. 高效数据处理技巧
2.1 列表推导式的艺术
列表推导式是Python最优雅的特性之一,它不仅能简化代码,在大多数情况下还能提供更好的性能。但过度使用嵌套推导式会降低可读性,需要权衡。
python复制# 基本列表推导式
squares = [x**2 for x in range(10)] # [0, 1, 4, 9, ..., 81]
# 带条件的推导式
even_squares = [x**2 for x in range(10) if x % 2 == 0]
# 嵌套推导式(矩阵转置)
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
transpose = [[row[i] for row in matrix] for i in range(3)]
性能对比:在处理百万级数据时,列表推导式通常比普通for循环快20%-30%。但在某些复杂逻辑下,生成器表达式可能更节省内存。
2.2 集合(Set)的去重与运算
集合的无序性和唯一性使其成为去重的理想选择。我在数据清洗中最常用的就是集合操作。
python复制# 基本去重
duplicates = ['a', 'b', 'a', 'c', 'b', 'a']
unique = set(duplicates) # {'a', 'b', 'c'}
# 集合运算
a = set('abracadabra')
b = set('alacazam')
print(a - b) # 差集: {'r', 'd', 'b'}
print(a | b) # 并集: {'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'}
print(a & b) # 交集: {'a', 'c'}
print(a ^ b) # 对称差: {'r', 'd', 'b', 'm', 'z', 'l'}
实用技巧:当需要判断元素是否存在且不关心顺序时,用集合比列表快得多(O(1) vs O(n))。我曾经用这个技巧优化过一个耗时很长的成员检查逻辑,性能提升了100倍。
2.3 字典(Dict)的高级用法
现代Python中(3.7+),字典保持插入顺序,这解决了很多历史问题。字典推导式让字典创建更加简洁。
python复制# 字典创建的各种方式
# 1. 直接键值对
d1 = {'name': 'Alice', 'age': 25}
# 2. 从键值对列表
d2 = dict([('name', 'Bob'), ('age', 30)])
# 3. 关键字参数
d3 = dict(name='Charlie', age=35)
# 4. 字典推导式
d4 = {x: x**2 for x in range(5)} # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
字典的默认值处理是实际开发中的常见需求,Python提供了几种优雅的解决方案:
python复制# 方法1:get()方法带默认值
count = word_count.get(word, 0)
# 方法2:collections.defaultdict
from collections import defaultdict
word_count = defaultdict(int) # 默认值为0
word_count[word] += 1
# 方法3:setdefault()方法
if key not in my_dict:
my_dict.setdefault(key, []).append(value)
3. 数据结构性能对比与选择策略
3.1 各数据结构时间复杂度对比
了解不同操作的性能特征对写出高效代码至关重要:
| 操作 | List | Set | Dict |
|---|---|---|---|
| 插入 | O(1)/O(n) | O(1) | O(1) |
| 删除 | O(1)/O(n) | O(1) | O(1) |
| 查找 | O(n) | O(1) | O(1) |
| 访问元素 | O(1) | N/A | O(1) |
注:列表的插入/删除在末尾是O(1),在开头或中间是O(n)
3.2 数据结构选择指南
根据我的经验,选择数据结构时应考虑以下因素:
-
是否需要保持顺序:
- 是:列表或元组
- 否:集合或字典
-
是否需要修改:
- 频繁修改:列表或集合
- 不修改:元组
-
是否需要快速查找:
- 是:集合或字典
- 否:列表或元组
-
数据关系:
- 键值对:字典
- 独立元素:列表/集合/元组
3.3 实际应用场景示例
场景1:处理百万级URL去重
- 错误选择:用列表存储并检查是否存在
- 正确选择:用集合存储,利用其O(1)的查找特性
场景2:维护一个按添加顺序排列的记录
- Python 3.7前:使用
collections.OrderedDict - Python 3.7+:普通字典即可
场景3:频繁在序列开头插入元素
- 错误选择:列表的insert(0, x)
- 正确选择:
collections.deque的appendleft()
4. 高级遍历与数据处理技巧
4.1 多序列并行遍历
zip()函数是处理多个序列的利器,它会自动在最短序列结束时停止:
python复制names = ['Alice', 'Bob', 'Charlie']
scores = [95, 87, 91]
for name, score in zip(names, scores):
print(f"{name}: {score}")
注意:Python 2中
zip()返回列表,而Python 3中返回迭代器。如需列表,需显式转换:list(zip(...))
4.2 带索引的遍历
enumerate()可以同时获取索引和值,避免手动维护计数器:
python复制# 传统方式(不推荐)
i = 0
for item in sequence:
print(i, item)
i += 1
# Pythonic方式
for i, item in enumerate(sequence, start=1): # start参数指定起始值
print(i, item)
4.3 字典的优雅遍历
现代Python提供了多种字典遍历方式:
python复制person = {'name': 'Alice', 'age': 25, 'job': 'Engineer'}
# 遍历键
for key in person: # 等同于 person.keys()
print(key)
# 遍历值
for value in person.values():
print(value)
# 遍历键值对
for key, value in person.items():
print(f"{key}: {value}")
4.4 排序遍历技巧
sorted()函数配合自定义排序键可以解决复杂排序需求:
python复制# 按值排序字典项
for key, value in sorted(person.items(), key=lambda item: item[1]):
print(f"{key}: {value}")
# 多级排序
students = [
{'name': 'Alice', 'grade': 'A', 'age': 20},
{'name': 'Bob', 'grade': 'B', 'age': 19},
{'name': 'Charlie', 'grade': 'A', 'age': 21}
]
# 先按grade升序,再按age降序
for student in sorted(students, key=lambda s: (s['grade'], -s['age'])):
print(student)
5. 数据结构间的转换技巧
5.1 列表与集合的互转
python复制# 列表转集合(去重)
numbers = [1, 2, 2, 3, 4, 4, 5]
unique_numbers = set(numbers) # {1, 2, 3, 4, 5}
# 集合转列表(注意顺序可能变化)
unique_list = list(unique_numbers)
5.2 字典与列表的转换
python复制# 字典键/值转列表
keys = list(person.keys())
values = list(person.values())
# 键值对列表转字典
pairs = [('name', 'Alice'), ('age', 25)]
person_dict = dict(pairs)
5.3 元组与列表的转换
python复制# 列表转元组(使其不可变)
mutable_list = [1, 2, 3]
immutable_tuple = tuple(mutable_list)
# 元组转列表(需要修改时)
modified_list = list(immutable_tuple)
modified_list.append(4)
6. 内存与性能优化技巧
6.1 浅拷贝与深拷贝
理解拷贝行为对避免bug至关重要:
python复制import copy
# 浅拷贝(只复制顶层)
original = [[1, 2], [3, 4]]
shallow = copy.copy(original)
shallow[0][0] = 99 # 会影响original!
# 深拷贝(递归复制所有层级)
deep = copy.deepcopy(original)
deep[0][0] = 100 # 不会影响original
6.2 生成器表达式节省内存
对于大数据处理,生成器表达式比列表推导式更节省内存:
python复制# 列表推导式(立即生成所有元素)
sum_of_squares = sum([x**2 for x in range(1000000)]) # 消耗大量内存
# 生成器表达式(惰性计算)
sum_of_squares = sum(x**2 for x in range(1000000)) # 内存友好
6.3 预分配列表空间
当知道列表最终大小时,预分配可以避免多次扩容:
python复制# 低效方式(多次扩容)
result = []
for i in range(10000):
result.append(i*2)
# 高效方式(预分配)
result = [0] * 10000 # 先创建足够大的列表
for i in range(10000):
result[i] = i * 2
7. 实际项目中的数据结构应用
7.1 配置文件解析
字典非常适合表示配置信息:
python复制config = {
'database': {
'host': 'localhost',
'port': 5432,
'user': 'admin'
},
'logging': {
'level': 'DEBUG',
'file': 'app.log'
}
}
# 访问嵌套配置
db_host = config['database']['host']
7.2 图结构表示
字典可以优雅地表示图结构:
python复制graph = {
'A': ['B', 'C'],
'B': ['A', 'D', 'E'],
'C': ['A', 'F'],
'D': ['B'],
'E': ['B', 'F'],
'F': ['C', 'E']
}
# 深度优先搜索
def dfs(graph, start, visited=None):
if visited is None:
visited = set()
visited.add(start)
print(start)
for neighbor in graph[start]:
if neighbor not in visited:
dfs(graph, neighbor, visited)
7.3 统计词频
字典是统计频率的理想选择:
python复制from collections import defaultdict
def word_frequency(text):
frequency = defaultdict(int)
for word in text.split():
frequency[word.lower()] += 1
return frequency
text = "This is a sample text with several words and this text is just a sample"
print(word_frequency(text))
8. Python 3.9+ 新特性
8.1 字典合并运算符
Python 3.9引入了更简洁的字典合并方式:
python复制# 传统方式
dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 3, 'c': 4}
merged = {**dict1, **dict2} # {'a': 1, 'b': 3, 'c': 4}
# Python 3.9+
merged = dict1 | dict2 # 更直观
8.2 类型提示支持
现代Python中可以为数据结构添加类型提示:
python复制from typing import List, Dict, Tuple, Set
def process_data(
names: List[str],
scores: Dict[str, float],
coordinates: Tuple[float, float],
unique_ids: Set[int]
) -> Dict[str, float]:
"""处理各种类型的数据并返回结果字典"""
# 函数实现...
return result
9. 调试与性能分析技巧
9.1 使用dis模块查看字节码
了解操作背后的实际成本:
python复制import dis
def test_list():
lst = []
lst.append(1)
lst.pop()
dis.dis(test_list)
9.2 使用timeit测量性能
比较不同数据结构的操作速度:
python复制from timeit import timeit
list_time = timeit('lst.append(1); lst.pop()', 'lst = []', number=1000000)
deque_time = timeit('d.append(1); d.pop()', 'from collections import deque; d = deque()', number=1000000)
print(f"List: {list_time:.3f} seconds")
print(f"Deque: {deque_time:.3f} seconds")
9.3 使用sys.getsizeof查看内存占用
python复制import sys
lst = list(range(1000))
tup = tuple(range(1000))
print(f"List size: {sys.getsizeof(lst)} bytes")
print(f"Tuple size: {sys.getsizeof(tup)} bytes")
10. 数据结构选择决策树
为了帮助你在实际开发中快速选择合适的数据结构,我总结了这个决策树:
-
需要存储键值对吗?
- 是 → 使用字典
- 否 → 进入2
-
需要保持元素唯一吗?
- 是 → 使用集合
- 否 → 进入3
-
需要修改内容吗?
- 是 → 使用列表
- 否 → 使用元组
-
需要频繁在两端操作吗?
- 是 → 考虑
collections.deque - 否 → 保持原选择
- 是 → 考虑
-
数据量非常大吗?
- 是 → 考虑生成器或特殊数据结构
- 否 → 保持原选择
11. 常见陷阱与解决方案
11.1 可变对象作为字典键
python复制# 错误示例
d = {}
lst = [1, 2, 3]
d[lst] = "value" # TypeError: unhashable type: 'list'
# 解决方案:使用元组
d[tuple(lst)] = "value" # 可行
11.2 循环中修改集合
python复制# 危险操作
s = {1, 2, 3}
for item in s:
s.add(item + 10) # RuntimeError: Set changed size during iteration
# 安全方式
for item in list(s): # 先创建副本
s.add(item + 10)
11.3 默认参数的陷阱
python复制# 错误示例
def add_to_list(value, lst=[]):
lst.append(value)
return lst
print(add_to_list(1)) # [1]
print(add_to_list(2)) # [1, 2] # 不是预期的[2]!
# 正确方式
def add_to_list(value, lst=None):
if lst is None:
lst = []
lst.append(value)
return lst
12. 数据结构在不同Python版本中的变化
12.1 字典顺序保持
- Python 3.6前:字典不保证顺序
- Python 3.6:实现细节保持顺序
- Python 3.7+:语言规范保证顺序
12.2 集合推导式语法
- Python 2.7+:引入集合推导式
{x for x in ...} - Python 3.0+:字典推导式语法变化
12.3 类型提示增强
- Python 3.5+:引入typing模块
- Python 3.9+:内置集合类型支持泛型语法
list[str]
13. 性能优化实战案例
13.1 大型数据去重
问题:处理包含1000万个URL的列表,去除重复项
低效方案:
python复制unique_urls = []
for url in all_urls:
if url not in unique_urls: # O(n)查找
unique_urls.append(url)
高效方案:
python复制unique_urls = list(set(all_urls)) # O(1)查找
13.2 频繁成员检查
问题:需要检查某元素是否存在于大型集合中
列表方案(慢):
python复制if item in my_list: # O(n)
pass
集合方案(快):
python复制if item in my_set: # O(1)
pass
13.3 多条件数据筛选
问题:从大型数据集中筛选满足多个条件的记录
低效方案:
python复制result = []
for record in data:
if condition1(record) and condition2(record) and condition3(record):
result.append(process(record))
高效方案:
python复制# 使用生成器表达式
result = (process(record) for record in data
if condition1(record) and condition2(record) and condition3(record))
14. 数据结构在算法中的应用
14.1 广度优先搜索(BFS)
python复制from collections import deque
def bfs(graph, start):
visited = set()
queue = deque([start])
while queue:
vertex = queue.popleft()
if vertex not in visited:
visited.add(vertex)
queue.extend(graph[vertex] - visited)
return visited
14.2 优先队列
python复制import heapq
def dijkstra(graph, start):
heap = [(0, start)]
visited = set()
while heap:
(cost, node) = heapq.heappop(heap)
if node not in visited:
visited.add(node)
for neighbor, c in graph[node].items():
heapq.heappush(heap, (cost + c, neighbor))
return visited
14.3 LRU缓存实现
python复制from collections import OrderedDict
class LRUCache:
def __init__(self, capacity):
self.cache = OrderedDict()
self.capacity = capacity
def get(self, key):
if key not in self.cache:
return -1
self.cache.move_to_end(key)
return self.cache[key]
def put(self, key, value):
if key in self.cache:
self.cache.move_to_end(key)
self.cache[key] = value
if len(self.cache) > self.capacity:
self.cache.popitem(last=False)
15. 数据结构与函数式编程
15.1 不可变数据结构的优势
python复制# 使用元组避免意外修改
def process_data(data):
# data是不可变的,不会被意外修改
return len(data), sum(data)
stats = process_data((1, 2, 3, 4, 5))
15.2 map/filter/reduce应用
python复制from functools import reduce
# map应用
squares = list(map(lambda x: x**2, range(10)))
# filter应用
evens = list(filter(lambda x: x % 2 == 0, range(10)))
# reduce应用
product = reduce(lambda x, y: x * y, [1, 2, 3, 4])
15.3 生成器与惰性求值
python复制def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
fib = fibonacci()
print(next(fib)) # 0
print(next(fib)) # 1
print(next(fib)) # 1
16. 数据结构与并发编程
16.1 线程安全的数据结构
python复制from queue import Queue
from threading import Thread
def worker(q):
while True:
item = q.get()
process(item)
q.task_done()
q = Queue()
for i in range(4):
Thread(target=worker, args=(q,), daemon=True).start()
for item in data:
q.put(item)
q.join()
16.2 多进程共享数据
python复制from multiprocessing import Manager
with Manager() as manager:
shared_list = manager.list()
shared_dict = manager.dict()
# 在多个进程中操作这些共享数据结构
17. 数据结构与面向对象设计
17.1 自定义集合类
python复制class CaseInsensitiveSet(set):
def __init__(self, iterable=()):
super().__init__(s.lower() for s in iterable)
def add(self, item):
super().add(item.lower())
def __contains__(self, item):
return super().__contains__(item.lower())
s = CaseInsensitiveSet(['Apple', 'Banana'])
print('apple' in s) # True
17.2 实现序列协议
python复制class CustomSequence:
def __init__(self, data):
self.data = data
def __len__(self):
return len(self.data)
def __getitem__(self, index):
return self.data[index]
def __contains__(self, item):
return item in self.data
seq = CustomSequence([1, 2, 3])
print(len(seq)) # 3
print(seq[1]) # 2
print(3 in seq) # True
18. 数据结构与元编程
18.1 动态属性访问
python复制class DynamicDict:
def __init__(self, data):
self._data = data
def __getattr__(self, name):
if name in self._data:
return self._data[name]
raise AttributeError(f"No attribute {name}")
d = DynamicDict({'name': 'Alice', 'age': 25})
print(d.name) # Alice
print(d.age) # 25
18.2 使用__slots__优化内存
python复制class Point:
__slots__ = ['x', 'y'] # 固定属性列表,节省内存
def __init__(self, x, y):
self.x = x
self.y = y
p = Point(3, 4)
print(p.x, p.y)
19. 数据结构与数据科学
19.1 使用namedtuple提高可读性
python复制from collections import namedtuple
Person = namedtuple('Person', ['name', 'age', 'job'])
alice = Person(name='Alice', age=25, job='Engineer')
print(alice.name) # 比alice[0]更可读
19.2 使用pandas处理表格数据
python复制import pandas as pd
# 从字典创建DataFrame
data = {
'Name': ['Alice', 'Bob', 'Charlie'],
'Age': [25, 30, 35],
'Salary': [50000, 60000, 70000]
}
df = pd.DataFrame(data)
# 高效筛选
high_earners = df[df['Salary'] > 55000]
20. 数据结构与Web开发
20.1 请求参数处理
python复制from flask import request
@app.route('/search')
def search():
# 请求参数本质是字典
query = request.args.get('q', '') # 等同于 request.args['q']但有默认值
page = int(request.args.get('page', 1))
# 处理逻辑...
20.2 JSON数据转换
python复制import json
# 字典与JSON互转
data = {'name': 'Alice', 'age': 25}
json_str = json.dumps(data) # 转为JSON字符串
data_back = json.loads(json_str) # 转回字典
21. 数据结构与测试
21.1 测试数据生成
python复制import random
def generate_test_data(num_records):
names = ['Alice', 'Bob', 'Charlie', 'David']
return [
{
'id': i,
'name': random.choice(names),
'score': random.randint(50, 100)
}
for i in range(num_records)
]
21.2 断言集合相等
python复制def test_set_operations():
a = {1, 2, 3}
b = {2, 3, 4}
assert a - b == {1} # 差集测试
assert a | b == {1, 2, 3, 4} # 并集测试
22. 数据结构与文件操作
22.1 CSV文件处理
python复制import csv
# 读取CSV到字典列表
with open('data.csv') as f:
reader = csv.DictReader(f)
data = [row for row in reader]
# 写入字典列表到CSV
with open('output.csv', 'w') as f:
writer = csv.DictWriter(f, fieldnames=['name', 'age'])
writer.writeheader()
writer.writerows(data)
22.2 配置文件解析
python复制import configparser
config = configparser.ConfigParser()
config.read('config.ini')
# 访问配置(本质是嵌套字典)
db_host = config['database']['host']
23. 数据结构与网络编程
23.1 处理API响应
python复制import requests
response = requests.get('https://api.example.com/users')
users = response.json() # 通常返回列表或字典
# 处理嵌套数据结构
for user in users:
print(user['name'], user['address']['city'])
23.2 URL参数构造
python复制from urllib.parse import urlencode
params = {
'q': 'python',
'page': 2,
'sort': 'relevance'
}
url = f"https://example.com/search?{urlencode(params)}"
24. 数据结构与日期时间处理
24.1 时间序列分组
python复制from collections import defaultdict
from datetime import datetime, timedelta
# 按小时分组事件
events = [...] # 包含datetime对象的列表
hourly_counts = defaultdict(int)
for event in events:
hour = event.replace(minute=0, second=0, microsecond=0)
hourly_counts[hour] += 1
24.2 工作日统计
python复制work_days = {
'Monday': 0,
'Tuesday': 0,
# ...其他工作日
}
for date in date_range:
day = date.strftime('%A')
if day in work_days:
work_days[day] += 1
25. 数据结构与正则表达式
25.1 分组匹配结果
python复制import re
text = "John: 25, Alice: 30, Bob: 28"
pattern = r'(\w+): (\d+)'
matches = re.findall(pattern, text) # 返回元组列表
# [('John', '25'), ('Alice', '30'), ('Bob', '28')]
# 转为字典
age_dict = {name: int(age) for name, age in matches}
25.2 命名分组
python复制pattern = r'(?P<name>\w+): (?P<age>\d+)'
match = re.search(pattern, text)
if match:
print(match.groupdict()) # {'name': 'John', 'age': '25'}
26. 数据结构与装饰器
26.1 使用字典实现注册表
python复制command_registry = {}
def register(name):
def decorator(fn):
command_registry[name] = fn
return fn
return decorator
@register('say_hello')
def hello():
print("Hello!")
@register('say_goodbye')
def goodbye():
print("Goodbye!")
# 执行注册的命令
command_registry['say_hello']()
26.2 带参数的装饰器
python复制def cache(max_size=100):
def decorator(fn):
cached_results = {}
keys_in_order = []
def wrapper(*args):
if args in cached_results:
return cached_results[args]
result = fn(*args)
cached_results[args] = result
keys_in_order.append(args)
if len(keys_in_order) > max_size:
oldest = keys_in_order.pop(0)
del cached_results[oldest]
return result
return wrapper
return decorator
@cache(max_size=50)
def expensive_computation(x):
# 耗时计算...
return result
27. 数据结构与上下文管理器
27.1 使用字典保存状态
python复制from contextlib import contextmanager
@contextmanager
def saved_state(obj, **kwargs):
original = {k: getattr(obj, k) for k in kwargs}
try:
for k, v in kwargs.items():
setattr(obj, k, v)
yield
finally:
for k, v in original.items():
setattr(obj, k, v)
class Config:
pass
config = Config()
config.debug = False
with saved_state(config, debug=True, log_level='verbose'):
print(config.debug) # True
print(config.debug) # False
27.2 事务处理模式
python复制class Transaction:
def __init__(self, data):
self.original = data.copy()
self.current = data
def __enter__(self):
return self.current
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type is not None: # 发生异常,回滚
self.current.clear()
self.current.update(self.original)
data = {'a': 1, 'b': 2}
with Transaction(data) as t:
t['a'] = 100
t['c'] = 3
# 如果这里抛出异常,修改会被回滚
28. 数据结构与异步编程
28.1 异步队列
python复制import asyncio
from collections import deque
class AsyncQueue:
def __init__(self):
self._queue = deque()
self._waiting = deque()
async def put(self, item):
self._queue.append(item)
if self._waiting:
self._waiting.popleft().set()
async def get(self):
while not self._queue:
future = asyncio.Future()
self._waiting.append(future)
await future
return self._queue.popleft()
28.2 异步缓存
python复制import asyncio
from functools import wraps
def async_cache(max_size=100):
cache = {}
keys = []
def decorator(fn):
@wraps(fn)
async def wrapper(*args):
if args in cache:
return cache[args]
result = await fn(*args)
cache[args] = result
keys.append(args)
if len(keys) > max_size:
oldest = keys.pop(0)
del cache[oldest]
return result
return wrapper
return decorator
@async_cache()
async def fetch_data(url):
# 异步获取数据
return data
29. 数据结构与类型系统
29.1 泛型容器
python复制from typing import TypeVar, Generic, List
T = TypeVar('T')
class Stack(Generic[T]):
def __init__(self) -> None:
self.items: List[T] = []
def push(self, item: T) -> None:
self.items.append(item)
def pop(self) -> T:
return self.items.pop()
# 使用类型提示
stack = Stack[int]()
stack.push(1)
stack.push(2)
value = stack.pop() # value会被推断为int类型
29.2 结构化类型
python复制from typing import Protocol, runtime_checkable
@runtime_checkable
class SupportsClose(Protocol):
def close(self) -> None: ...
def close_all(resources