python语言中的常用容器(集合)示例详解
前言先说一个措辞问题。这个标题里的「容器」和「集合」其实是两个层级的概念不该并列。容器container是上位概念指任何用来装一组对象的类型Python 内置的list、tuple、dict、set、str都属于容器而集合set是其中一个具体的类型特指无序、元素唯一的那种容器。标题写成「常用容器(集合)」容易让人误以为「容器就等于集合」。准确的表述应该是「常用容器含集合」。顺带说一句英文里collection也常被翻译成「集合」那是指更宽泛的「一组对象」和set这个具体类型不是一回事。collections模块名字里的那个collections就是前者。本文按「四类内置容器逐个过一遍 横向对比 各自示例」的结构把list、tuple、dict、set一次讲清重点放在set上。一、四个内置容器总览先看一张总表把四者的关键差别对齐。容器字面量写法可变有序可哈希成员判断典型场景list[1, 2]是是否O(n)有序、可变、允许重复的数据tuple(1, 2)否是元素可哈希时是O(n)固定记录、当字典键dict{a: 1}是3.7 起保证插入顺序否O(1) 平均键值映射set{1, 2}是否否O(1) 平均去重、存在性判断几个必须记住的细节{}是空字典空集合只能写set()空列表是[]空元组是()。dict和set的成员判断都是哈希定位平均 O(1)list和tuple要逐个比。dict的键必须可哈希set的元素也必须可哈希它们的内核是同一套哈希表。tuple不可变所以元素都可哈希时整体可哈希list可变永远不可哈希。二、list最常用的可变序列列表按位置组织数据支持下标、切片、增删改允许重复元素。# 适用于 Python 3.8fruits [apple, banana, cherry]fruits.append(date) # 尾部追加fruits.insert(0, avocado) # 指定位置插入fruits.remove(banana) # 按值删除不存在则抛 ValueErrorprint(fruits) # [avocado, apple, cherry, date]print(fruits[1]) # appleprint(sorted(fruits)) # 返回排序后的新列表# 注意 sort() 原地排序并返回 Noneret fruits.sort()print(ret) # Noneprint(fruits) # 排序后的列表本身最后三行是一个高频坑list.sort()原地排序、返回None而内置函数sorted()返回新列表。把fruits fruits.sort()写出来fruits就变成None了。三、tuple不可变序列元组和列表的读取方式一样区别在于不能改。# 适用于 Python 3.8point (3, 5)print(point[0], point[1]) # 3 5# 单元素元组的逗号不能省one (1,)print(type(one).__name__) # tupleprint(type((1)).__name__) # int这个是整数# 解包x, y pointprint(x, y) # 3 5元组只有count和index两个专属方法。因为它不可变所以能被当成字典的键、放进集合这是列表做不到的。四、dict键值映射字典保存键到值的映射从 3.7 起保证插入顺序3.6 只是实现细节不要依赖 3.6 的行为。# 适用于 Python 3.8student {name: 小明, age: 12}student[grade] 6 # 新增键student[age] 13 # 覆盖已有键print(student[name]) # 小明print(student.get(score)) # None键不存在返回 Noneprint(student.get(score, 0)) # 0可以给默认值print(list(student.keys())) # [name, age, grade]插入顺序d[key]在键不存在时抛KeyErrord.get(key)返回None——这是两者最重要的区别。另外从 3.9 起有|合并运算符PEP 5843.8 及更早版本要用{**a, **b}。# 适用于 Python 3.9other {city: 北京}merged student | otherprint(sorted(merged.keys())) # [age, city, grade, name]# 适用于 Python 3.8替代 3.9 的 | 合并运算符other {city: 北京}merged {**student, **other}print(sorted(merged.keys())) # [age, city, grade, name]五、set无序且唯一集合放进去的元素唯一、无序。它的两个核心用途是去重和快速判断存在。# 适用于 Python 3.8# 去重tags [python, web, python, async]unique set(tags)print(sorted(unique)) # [async, python, web]# 空集合必须用 set()empty set()print(type(empty).__name__) # set# 成员判断平均 O(1)print(web in unique) # True# 集合运算a {python, async, web}b {python, packaging}print(sorted(a b)) # [python]交集print(sorted(a | b)) # 并集print(sorted(a - b)) # 差集集合要求元素可哈希数字、字符串、bytes、frozenset可以tuple在内部元素都可哈希时可以list、dict、set不行。# 适用于 Python 3.8print(set((1, 2, 3))) # {(1, 2, 3)}元组可哈希print(set([1, 2])) # {1, 2}列表是「输入」而不是「元素」try:bad {[1, 2], [3, 4]}except TypeError as e:print(报错, e) # unhashable type: list# 换成元组就合法也能表示「集合的集合」good {(1, 2), (3, 4)}print(len(good)) # 2这两段的对比值得琢磨set(某列表)是把列表当输入集合会逐个取出列表里的元素所以它当然可以是不可哈希的东西而{某列表}是把列表当元素这时才要求可哈希。六、横向对比示例下面用同一份数据分别用四种容器处理直观感受取舍。# 适用于 Python 3.8raw [alice, bob, alice, carol]as_list list(raw) # 保留全部含重复as_tuple tuple(raw) # 同上但不可变as_counts {} # 统计出现次数for name in raw:as_counts[name] as_counts.get(name, 0) 1as_set set(raw) # 只留唯一值print(as_list) # [alice, bob, alice, carol]print(as_tuple[0]) # aliceprint(as_counts) # {alice: 2, bob: 1, carol: 1}print(sorted(as_set)) # [alice, bob, carol]# 顺序敏感的去重3.7 起 dict 保序ordered_unique list(dict.fromkeys(raw))print(ordered_unique) # [alice, bob, carol]逐行推演raw有四个元素alice出现两次。as_list原样保留。as_counts用get(name, 0) 1累加得到每个名字的次数。as_set去掉重复只剩三个。最后的dict.fromkeys(raw)按顺序建字典键就是去重后的名字再转回列表就得到保序去重结果——这是「既要去重又要保序」的标准写法依赖的是字典 3.7 起保证插入顺序这条官方承诺。七、实战统计标签并比较两组# 适用于 Python 3.8def tag_stats(rows):rows 是 (文章标题, 标签列表) 的列表统计每个标签出现次数。counts {}for title, tag_list in rows:for tag in tag_list:counts[tag] counts.get(tag, 0) 1return countsdef common_tags(rows_a, rows_b):找出两组文章共有的标签。a {tag for _, tags in rows_a for tag in tags}b {tag for _, tags in rows_b for tag in tags}return sorted(a b), sorted(a - b), sorted(b - a)if __name__ __main__:group_a [(t1, [python, web]), (t2, [python, test])]group_b [(t3, [python, packaging])]stats tag_stats(group_a)print(sorted(stats.items())) # [(python, 2), (test, 1), (web, 1)]shared, only_a, only_b common_tags(group_a, group_b)print(共有, shared) # 共有 [python]print(只在 A, only_a) # 只在 A [test, web]print(只在 B, only_b) # 只在 B [packaging]逐行推演tag_stats用字典累加每个标签的出现次数counts.get(tag, 0)在标签首次出现时给 0。common_tags用集合推导式把两组的标签分别收集成集合再做交集和两个方向的差集。sorted(stats.items())把键值对按元组排序后打印。整段只用到 dict 和 set 的基础用法。常见坑点坑点 1把{}当成空集合。❌s {}; s.add(1)——{}是空字典抛AttributeError: dict object has no attribute add。 ✅ 空集合写s set()。坑点 2把list.sort()的返回值赋回去。❌items items.sort()——原地排序返回Noneitems变成None。 ✅ 直接items.sort()要新列表就用items sorted(items)。坑点 3dict用[]取不存在的键。❌d[missing]——抛KeyError。 ✅ 允许缺省时用d.get(missing)或带默认值的d.get(missing, 0)。坑点 4以为集合保持插入顺序。❌list(set([b, a]))期待得到[b, a]——集合无序。 ✅ 保序去重用list(dict.fromkeys([b, a]))得到[b, a]。坑点 5把不可哈希对象放进集合或当字典键。❌{[1, 2]}或d {[1, 2]: x}——抛TypeError: unhashable type: list。 ✅ 换成元组或字符串{(1, 2)}、d {(1, 2): x}。坑点 6以为set(某列表)会因为列表不可哈希而报错。❌ 看到「集合元素必须可哈希」就以为set([1, 2])非法——它完全合法参数是被迭代的对象不是元素。 ✅ 分清「作为输入」和「作为元素」set([1, 2])得到{1, 2}{[1, 2]}才报错。坑点 7用拼接集合。❌{1} {2}——集合不支持抛TypeError。 ✅ 用并集{1} | {2}或{1}.union({2})得到{1, 2}。坑点 8以为dict和set的in也很快却用错了对象。❌x in [a, b, ...]对长列表反复判断——这是 O(n) 扫描。 ✅ 先把列表转成集合再判断x in set(big_list)之后每次判断平均 O(1)。总结需求选哪个关键理由有序、会增删改list可变、支持下标与切片固定不变的一组值tuple不可变可当键和集合元素键到值的映射dict平均 O(1) 按键查找3.7 起保序去重 / 判断存在 / 集合运算set元素唯一平均 O(1) 成员判断需要可哈希的集合frozenset不可变所以可哈希「容器」是一个大类「集合」只是其中一员。选容器时按顺序问三个问题需要键值映射吗dict需要去重或纯存在性判断吗set需要之后修改吗list / tuple三个问题问完选型基本就定了。

相关新闻

Kubernetes LoadBalancer原理与MetalLB/BGP实战部署

Kubernetes LoadBalancer原理与MetalLB/BGP实战部署

1. 项目概述:为什么K8s集群里LoadBalancer不是“开箱即用”的魔法按钮?在某次给某高校实验室做容器化教学支持时,一位刚接触云原生的导师直接问我:“K8s文档里写的LoadBalancer类型Service,我yaml一写,服务…

2026/10/13 13:21:27 阅读更多 →
AI编码工具的正向价值与工程风险实战指南

AI编码工具的正向价值与工程风险实战指南

1. 这不是“AI写代码”,而是工程师与工具的新型协作关系最近在几个技术社区里,看到不少开发者发帖问:“Copilot生成的代码能直接上线吗?”“用AI写完功能,自己反而不会调试了?”“团队开始用AI辅助开发&…

2026/10/13 13:21:06 阅读更多 →
ResNet实战:用PyTorch在CIFAR-10上稳定达到92%准确率的完整流程

ResNet实战:用PyTorch在CIFAR-10上稳定达到92%准确率的完整流程

简介:资源包面向深度学习初学者与图像分类实践者,围绕ResNet在CIFAR-10数据集上的分类任务,提供了完整的算法实现与使用说明。包体共5个文件,包含4个Python脚本,分别对应模型结构搭建、数据预处理、训练流程与推理预测…

2026/10/13 13:21:08 阅读更多 →

最新新闻

ETL实操手记:稳定性、可追溯性与业务语义落地

ETL实操手记:稳定性、可追溯性与业务语义落地

1. 项目概述:这不是一份简历,而是一份ETL实操手记“ETL工作经验分享(1)”——看到这个标题,别急着划走。它不是那种罗列“熟悉Kettle、会写SQL、了解DataStage”的简历式总结,也不是教科书里抽象的“抽取-转…

2026/10/13 15:10:42 阅读更多 →
Elastic-Job分布式任务调度:分片、高可用与生产实践

Elastic-Job分布式任务调度:分片、高可用与生产实践

做过定时任务的都知道,单机版Quartz写起来很爽,但一上生产、多节点部署,问题立马就堆过来了:任务重复执行、机器挂了没人接管、数据量大了单机扛不住。今天要聊的Elastic-Job,就是专门解决这类分布式场景下任务调度痛点…

2026/10/13 15:10:42 阅读更多 →
XGBoost工程实战手册:从安装配置到可解释调参

XGBoost工程实战手册:从安装配置到可解释调参

简介:本资源是Jason Brownlee撰写的英文原版经典教程《XGBoost with Python》PDF电子书,面向具备Python与机器学习基础的开发者、数据分析师及进阶学习者,系统解决梯度提升建模中原理理解难、XGBoost实操门槛高、参数调优无从下手等核心问题。…

2026/10/13 15:10:42 阅读更多 →
数学建模竞赛实战指南:从组队分工到论文写作的全流程经验

数学建模竞赛实战指南:从组队分工到论文写作的全流程经验

我不是啥机构认证的竞赛导师,就是一个带队参赛过很多次的老学长。这些年我带过的队伍,有拿奖拿到手软的,也有三天三夜肝到崩溃最后连成功参赛奖都没混上的。你问我数学建模竞赛(MCM)到底难不难?我的答案是&…

2026/10/13 15:10:42 阅读更多 →
为什么TCP要“动态适应网络特性“?用“开车根据路况调整速度“比喻。

为什么TCP要“动态适应网络特性“?用“开车根据路况调整速度“比喻。

核心比喻: TCP发送数据,就像你开车拉货,从A地送到B地。 你的货车 发送方主机货物 TCP分段(前面的拼图碎片)公路 网络链路路上堵车、事故、限速 网络拥塞(路由器排队、丢包、延迟变大)拥塞窗…

2026/10/13 15:10:42 阅读更多 →
基于模型的测试(MBT)实战:状态机建模与用例自动生成

基于模型的测试(MBT)实战:状态机建模与用例自动生成

1. 为什么我会推荐把MBT放进测试技术栈1.1 传统用例设计的三道坎做测试这行时间长了,你会慢慢发现一个有意思的现象:真正让人头疼的不是测试执行,而是测试设计。需求评审完了,开发方案定了,接下来就是用例设计。但用例…

2026/10/13 15:09:41 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →