03 容器、切片与解包
大约 2 分钟编程语言Python数据结构容器迭代器
03 容器、切片与解包
容器选择应先回答访问方式、顺序、唯一性和可变性,而不是先背 API。
1. 容器选型
| 需求 | 首选 |
|---|---|
| 有序、允许重复、频繁追加 | list |
| 固定记录、可哈希、需要解包 | tuple |
| 按键查找、插入顺序 | dict |
| 去重、集合运算 | set |
| 不可变集合 | frozenset |
| 队列两端高效操作 | collections.deque |
| 计数 | collections.Counter |
| 分组累加 | collections.defaultdict |
2. 切片
切片返回新序列,不修改原序列:
values = list(range(10))
print(values[:3])
print(values[-3:])
print(values[2:8:2])
print(values[::-1])切片中的 start、stop 可以是边界外的值;单个索引越界会抛出 IndexError。
3. 推导式
numbers = range(10)
squares = [number * number for number in numbers if number % 2 == 0]
lookup = {number: number * number for number in numbers}
unique_mod = {number % 3 for number in numbers}推导式适合简单转换。包含复杂条件、异常处理或多个副作用时,改用普通循环更清楚。
4. 解包
host, port = ("127.0.0.1", 8080)
first, *middle, last = [1, 2, 3, 4, 5]
config = {"timeout": 5, "retries": 2}
merged = {"enabled": True, **config}
def request(method, url, *, timeout=5, verify=True):
return method, url, timeout, verify
print(request("GET", "/health", timeout=3))星号解包会把可迭代对象展开。参与合并的映射必须具有字符串键,后面的键会覆盖前面的同名键。
5. 排序与分组
from collections import defaultdict
from itertools import groupby
events = [
{"service": "api", "level": "ERROR"},
{"service": "db", "level": "WARN"},
{"service": "api", "level": "WARN"},
]
by_level = defaultdict(list)
for event in events:
by_level[event["level"]].append(event["service"])
events_by_level = sorted(events, key=lambda item: item["level"])
for level, group in groupby(events_by_level, key=lambda item: item["level"]):
print(level, [item["service"] for item in group])groupby 只合并相邻的相同键;需要全局分组时先排序,或直接使用 defaultdict。
6. 浅拷贝与深拷贝
import copy
original = {"items": [1, 2]}
shallow = original.copy()
deep = copy.deepcopy(original)
shallow["items"].append(3)
print(original)
print(deep)浅拷贝只复制外层容器,内外层仍可能共享对象。配置快照、缓存和并发共享状态尤其要明确拷贝层级。
7. 迭代器与生成器
def stream_lines(lines):
for line in lines:
stripped = line.strip()
if stripped:
yield stripped
for line in stream_lines(["alpha\n", "\n", "beta\n"]):
print(line)生成器逐个产生结果,适合处理大文件、日志流和不需要一次性装入内存的数据。生成器只能消费一次,需要重复遍历时先明确是否应转换为列表。
8. 常见陷阱
- 遍历列表时删除元素,导致跳过项目;应构造新列表或倒序删除。
- 用
list做大批量成员判断,复杂度通常比set更高。 - 误以为
dict的值有序就代表可以做复杂排序规则。 - 修改正在迭代的字典。
- 把浅拷贝当成完全隔离。
- 无限生成器上调用
list()。
