Python 数据类型与数据结构
Python 内置类型总图:标量、序列、映射、集合与二进制类型;用可变/不可变与典型场景建立阶段二阅读入口。
#type / concept
#status / growing
#resource / python
#tech / lang / python
#tech / dev
[!info] 关联笔记
Python 数据类型与数据结构
这个概念为什么出现
Python 日常编码 80% 的时间在和内置容器与标量打交道。没有一张总图时,人容易:
- 该用
tuple却用了list - 该用
set去重却手写双重循环 - 把
bytes当str处理网络报文
本篇是地图,不是把每个容器写到实现级;细规则由阶段二原子笔记承担。
[!abstract] 一句话理解 Python 内置类型按标量、序列、映射、集合与二进制分组;先判断“是否可变、是否有序、键/元素约束”,再选结构。
最小可运行示例
先把示例放进业务场景,再看代码:
场景:活动报名后台做一次轻量汇总
运营后台读到一批报名记录,需要:
- 用
list保序展示 - 用
set统计去重用户 - 用
dict聚合渠道计数 - 用
tuple做不可变的配置键
# signup_structures_map.py
# 业务意图:用四种核心容器完成报名汇总。
# 教学点:
# - list 有序可改;tuple 有序不可变;
# - set 去重;dict 做聚合;
# - 容器里装的是对象引用。
from collections import Counter
def summarize_signups(rows: list[dict]) -> dict:
# rows: [{"user": "u1", "channel": "wechat"}, ...]
ordered_users = [] # 保序展示(可含重复报名意图时另议)
unique_users: set[str] = set()
for row in rows:
ordered_users.append(row["user"])
unique_users.add(row["user"])
channel_counts = Counter(row["channel"] for row in rows)
# 不可变配置键示例:环境 + 活动代码
cache_key = ("prod", "spring-sale")
return {
"ordered_users": ordered_users,
"unique_count": len(unique_users),
"channels": dict(channel_counts),
"cache_key": cache_key,
}
def main() -> None:
rows = [
{"user": "alice", "channel": "wechat"},
{"user": "bob", "channel": "app"},
{"user": "alice", "channel": "wechat"},
]
print(summarize_signups(rows))
if __name__ == "__main__":
main()
建议运行:
python signup_structures_map.py
期望输出:
{'ordered_users': ['alice', 'bob', 'alice'], 'unique_count': 2, 'channels': {'wechat': 2, 'app': 1}, 'cache_key': ('prod', 'spring-sale')}
结合场景再看三个关注点
- 同一用户出现两次:list 保留事件流,set 回答“多少独立用户”。
- dict/Counter 适合聚合;不要滥用 list 线性扫描当主索引。
- tuple 作键要求元素可哈希;list 不能当 dict 键。
核心概念与准确模型
内置类型地图
| 类别 | 类型 | 有序 | 可变 | 典型场景 |
|---|---|---|---|---|
| 数值 | int, float, complex | — | 否 | 计数、度量 |
| 文本 | str | 是 | 否 | 文案、标识 |
| 布尔/空 | bool, None | — | 否 | 标志、缺失 |
| 序列 | list, tuple, range | 是 | list 是 / 其余否 | 列表、记录、范围 |
| 映射 | dict | 插入序 | 是 | 索引、JSON 对象 |
| 集合 | set, frozenset | 否 | set 是 | 去重、成员测试 |
| 二进制 | bytes, bytearray, memoryview | 是 | 仅 bytearray 等 | 网络、文件 |
可变与不可变(总原则)
- 不可变:对象值不可改;“修改”通常产生新对象再绑定。
- 可变:可原地改;多名字共享时彼此可见。
- 容器不可变 ≠ 其元素若可变就“深不可变”(
tuple可装list)。
选择启发式
- 要索引与保序可变序列 →
list - 固定字段小记录 / 可哈希序列 →
tuple - 键值检索与聚合 →
dict - 去重与集合运算 →
set - 文本 →
str;字节协议 →bytes
边界情况与反直觉行为
- 空容器真值:空
list/dict/set/""为假。 - dict 键必须可哈希;自定义对象需正确
__hash__/__eq__。 - 大 list 头删
pop(0)昂贵;队列场景看deque。
常见误区
[!warning] 常见误区:只有 list 一种序列 错误理解:所有一串数据都用 list。
正确模型:固定结构、作键、防误改时优先 tuple;成员测试频繁用 set。
工程实践
- API 边界:输入 list/dict 是否会被函数原地修改要写清。
- JSON 对应:object→dict,array→list,string→str,null→None。
- 性能:先选对结构,再谈微观优化。
本节总结
本篇给你选型地图。下一步应按路线进入 list/tuple、dict、可变性与字符串专篇,而不是在一页堆完所有方法表。
自测题
- 为什么
cache_key用 tuple 而不是 list? - 统计独立用户为什么需要 set(或等价结构)?
参考答案
- 需要不可变且可哈希,才能稳定当键/缓存标识;list 不可哈希。
- set 平均 O(1) 成员测试/去重,表达“集合”语义比双层 list 扫描清晰。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| Built-in Types | 文档 | 类型行为 |
| Tutorial – Data Structures | 教程 | 容器入门 |