python语言中的常用容器(集合)示例详解

发布时间:2026/10/12 12:41:51

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三个问题问完选型基本就定了。
延伸阅读

更多相关文章

2026/10/12 12:41:51

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

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

2026/10/12 12:36:51

Windows批处理驱动MATLAB自动参数扫描:原理与实战

在Windows下用批处理自动运行MATLAB并不断更改参数,是我在做参数扫描仿真时被逼出来的一套方案。当时要跑十几组参数,每组运行三分钟,手动改参数、点运行、等结果、再复制数据,整个人像机器人一样盯屏幕。后来我用了一个最简单的办…

2026/10/12 12:36:51

Open Claw开源机械爪:低成本3D打印与舵机控制实战指南

1. 项目概述:Open Claw是什么,能做什么先明确一下,Open Claw是一个完全开源的机械爪项目。我看到这个标题时第一反应是:终于有人把机械爪从实验室里解放出来了。过去几年,机械臂、仿生机器人被炒得很热,但你…

2026/10/12 13:42:00

REDox 64位token统一表示:多格式互转与内存降70%

1. 从"数据格式地狱"说起:REDox 到底在解决什么问题做数据工程或者后端开发的人,大概率都经历过这样的场景:上游给过来一批 JSON,下游要转成 YAML 做配置,再往后还要塞进 TOML 给某个工具链用,中…

2026/10/12 13:42:00

RAG落地实战:LangChain、向量检索与重排优化指南

简介:面向大模型与人工智能开发者的实战型PDF文档,系统演示如何基于LangChain从零实现一个RAG问答应用。文档选取百度百科中的藜麦数据模拟个人或企业私域数据,完整覆盖项目策划、环境搭建(CUDA 11.7、Python 3.10、PyTorch 1.13.…

2026/10/12 13:42:00

Python协同过滤电影推荐系统毕设:ItemCF源码、评估与论文避坑指南

简介:这是一套面向计算机相关专业毕业设计场景的完整项目资料,以Python实现基于协同过滤算法的电影推荐系统,适合正在准备毕设、课程设计或期末大作业的学生,以及需要推荐算法实战练习的学习者。资源包共约2000个文件,…

2026/10/12 13:42:00

浏览器里重造经典回合制RPG:TypeScript与可视化编辑器实战

1. 为什么要在浏览器里重造一款二十多年前的回合制角色扮演游戏把一款经典回合制角色扮演游戏从零搬到浏览器里,这件事听起来像是情怀驱动,但真正动手之后你会发现,它其实是一次对前端工程能力的全面体检。我最初起这个念头的场景很具体&…

2026/10/12 13:42:00

TypeScript重写仙剑奇侠传:游戏引擎与可视化编辑器全流程

1. 项目缘起与整体架构设计1.1 为什么选择重写经典 RPG 而不是做个新游戏第一次冒出重写《仙剑奇侠传》的念头,其实源于一次很偶然的尝试。当时我想在浏览器里重温一下这款老游戏,发现要么需要装各种模拟器,要么找到的网页版操作手感极差&…

2026/10/11 0:02:13

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/12 12:01:26

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/12 12:54:07

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/12 0:04:22

绝缘子缺陷检测数据集清洗与工业级训练实战指南

简介:本资源是面向电力AI研发人员、工业视觉工程师及智能巡检系统开发者的绝缘子缺陷检测专用YOLO格式数据集,解决无人机航拍场景下绝缘子破损、污闪、积雪等9类典型缺陷的精准识别与定位难题。数据集共2139张真实巡检图像(含训练/验证/测试集…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑