【Python3基础】05-容器数据类型

发布时间:2026/10/19 1:58:47
【Python3基础】05-容器数据类型 [TOC] 系列文章导航【Python3基础】01-Python 环境与开发工具【Python3基础】02-输入输出与程序运行【Python3基础】03-基本数据类型与表达式【Python3基础】04-字符串与格式化【Python3基础】05-容器数据类型【Python3基础】06-条件判断与循环【Python3基础】07-函数基础与参数设计【Python3基础】08-高阶函数、闭包与装饰器【Python3基础】09-切片、推导式与迭代协议【Python3基础】10-类与对象【Python3基础】11-继承、多态与对象协议【Python3基础】12-动态类型与元编程【Python3基础】13-Python 常用设计模式【Python3基础】14-模块、包与虚拟环境【Python3基础】15-文件、目录与内存流【Python3基础】16-序列化、异常与调试【Python3基础】17-常用标准库与第三方库【Python3基础】18-多进程、多线程与协程【Python3基础】19-Socket 与 TCP、UDP 编程【Python3基础】20-网络应用与异步 IO概述列表管顺序字典管映射集合管唯一性元组管稳定结构。Python 的四种常用容器各有侧重。本篇按照“是否有序、是否可变、元素是否唯一、如何查找”四个维度讲解list、tuple、dict和set并通过增删改查与遍历操作说明它们的典型用法。本篇知识路线list [A, B, A] 有序、可变、可重复 tuple (A, B, A) 有序、不可变、可重复 dict {key: value} 按键映射 set {A, B} 元素唯一、支持集合运算list类型基本数据类型是其它语言都必有的数据类型但 list 数据类型在其它语言中并不一定是内置的数据类型比如 c 语言c 里面的 list 可以是第三方的 stl 库提供的 也可以是程序员自己创造的一种数据类型但是 Python 解释器内置 list 数据类型。list 是 Python 内置的一种数据类型list 是一种有序的集合有序集合并不是集合里面的数据是有序的 有序集合的意思是可以通过下标访问的集合有序集合的概念我们在上一小节提到在此重述一遍。list 定义因为 python 是动态语言定义一个 list 变量不需要显式的定义 listlist定义是用 [] 或者 list([])我们以后习惯于直接用 []因为书写简单易懂[] 里面的数据是 list 的成员。ugly_list[ruhua,xingxing,konglong]print(ugly_list)当然如果 [] 里面可以不放入数据也是一个 list是一个空的 list。注意空 list 是假值。beauty_list[]print(beauty_list)ifnotbeauty_list:print(beauty_list 是假值)可以通过下标来访问 list 中的成员索引是从 0 开始的list 是变量我们可以通过下标修改 list 成员的值。ugly_list[ruhua,xingxing,konglong]print(ugly_list[0])# 通过下标访问成员ugly_list[1]zhaoritian# 通过下标修改成员print(ugly_list)操作 list 常用的函数上节我们知道 len 函数是 Python 内置的函数并且可以用于获取字符串长度同样 len 函数可以获得 list 的长度。ugly_list[ruhua,xingxing,konglong]print(len(ugly_list))可以通过 list 的 index 函数获取成员所在的下标 如果指定 start 和 stop 范围则在指定范围左闭右开内查找 如果该成员不存在则 Python 解释器抛出异常。ugly_list[ruhua,xingxing,konglong]print(ugly_list.index(xingxing))# 返回下标 1print(ugly_list.index(zhaoritian))# 抛出异常print(ugly_list.index(konglong,0,2))# 抛出异常因为范围在[0,2)我们知道通过下标可以访问和修改成员的值但无法添加值 我们可以通过 list 的 insert 函数插入元素到 list 中的某个位置。ugly_list[ruhua,xingxing,konglong]ugly_list.insert(1,zhaoritian)print(ugly_list)可以用 list 的 pop 函数删除所指定的索引的成员如果索引不存在越界则 Python 解释器抛出异常 remove 函数可以删除指定的成员如果该成员不存则 Python 解释器抛出异常。# pop 函数ugly_list[ruhua,xingxing,konglong]ugly_list.pop(1)# okprint(ugly_list)ugly_list.pop(10)# 抛出异常因为索引越界print(ugly_list)# remove 函数ugly_list[ruhua,xingxing,konglong]ugly_list.remove(xingxing)# okprint(ugly_list)ugly_list.remove(zhaoritian)# 抛出异常因为成员不存在print(ugly_list)list 成员的本质list 中的成员可以是任何类型成员的数据类型也可以不同 空 list 用 [] 表示我们前面讲过 [] 是假值但是 [] 不是 False 也不是 None更不是 0 或 “”因为数据类型不同。mylist[Hello,250,[1,2,3]]print(mylist)otherlist[]print(otherlistFalse)# Falseprint(nototherlist)# Truelist 中的成员用逗号隔开每个成员无论数据类型多么复杂也只是一个成员。mylist[Hello,250,[1,2,3]]len_mylistlen(mylist)print(len_mylist)# 结果为 3print(mylist[0])# Helloprint(mylist[2])# [1, 2, 3]mylist[2][1]5# 正确[1, 2, 3] 是变量里面的成员可以修改mylist[0][1]F# 错误Hello 是常量里面的成员不可修改tuple类型在我们现实世界中存在一些不变的数据比如身份证号学号等等 在程序里我们可以用 list 来存储一个班级里面所有学生的学号 但 list 本身可以修改成员值有可能在我们程序中不小心修改了 list 成员值导致业务逻辑错误但在语法上并不存在问题给程序员排查问题带来困难 所以用 list 来存储学号并不能很好的描述现实世界Python 提供了 tuple元组 数据类型来更好的描述这种现实世界的问题。tuple 与 list 类似也是一种有序的集合不同之处在于 tuple 中的成员是不可改变的不能添加新成员不能删除已有的成员不能修改里面的成员值。tuple 定义元组使用小括号列表使用方括号元组创建很简单只需要在括号中添加成员 并使用逗号隔开即可。students_id(1001,1002,1003)print(students_id)如果要定义一个空的 tuple可以写成 ()。 如果要定义只有 1 个成员的 tuple不能写成 (x) 要写成 (x,)因为 () 不但可以定义 tuple 类型也可以作为运算符比如 (1) 可以认为是对整数 1 做 () 运算因为 () 的运算符优先级最高Python 解释器会把 (1) 看作为对 1 做 () 运算。tupleone()# 空的 tupleprint(tupleone)tupletwo(1,)# 一个成员的 tupleprint(tupletwo)tupletwo(1)# int 类型的 1print(tupletwo)tuple 里面的成员不可修改所以它没有 appendinsert 等可以修改集合成员的函数其它获取成员的函数和 list 相似因为 tuple 不可变所以代码更安全。如果可以能用 tuple 代替 list 就尽量用 tuple。深度剖析 tuple 内存模型tuple 不可改变 也就是说 tuple 在刚开始定义的时候 里面的成员就确定了我们不能修改添加删除 tuple 成员 但是如果 tuple 里面某个成员本身是可以改变的类型比如 list 我们可以改变这个变量成员本身内的值注意我们并没有改变 tuple 的成员我们修改的是 tuple 成员中的成员。mytuple(Hello,250,[1,2,3])mytuple[2][0]Python# 可以print(mytuple)我们分析以上代码每一步在内存中是如何表示的对于第一行代码mytuple (Hello, 250, [1, 2, 3])的内存模型如下图。对于第二行代码mytuple[2][0] Python的内存模型如下图。通过上面对那两句代码的内存模型的图解析我们可以清晰的看到无论是原来的 tuple (“Hello”, 250, [1, 2, 3]) 还是后面的 tuple (“Hello”, 250, [“Python”, 2, 3])对于 tuple 本身的成员来说并没有变化还是那些地址值只是 tuple 的第二个成员 [1, 2, 3] 里面的成员发生了变化 所以并没有违背 tuple 的规则tuple 成员不可改变。tuple 里面的成员是用逗号隔开的每个成员可以是任何数据类型无论该成员多么复杂对 tuple 来说只是一个成员。mytuple(Hello,250,[1,2,3])print(len(mytuple))# 3dict类型假设我们需要用一个数据结构来存储 3 万个汉字如果我们使用 list 或 tuple 来存储当我们查找某个汉字时 就需要从第一个成员开始一直找直到我们能找到或者到最后一个成员没有找到为止。dict 就是字典其实现原理和我们使用的字典是一样的假设我们使用 dict 来存储 3 万个汉字我们只需要在字典的索引表里查这个汉字对应的位置就可以找到这个字无论找哪个字我们都可以一次性定位到该字也就是时间复杂度为 o(1)。 我们使用 dict 数据结构来存储汉字查找速度不会随着汉字内容的多少而变化。对于我们前面学过的 str 类型list 类型和 tuple 类型都可以通过下标访问里面的成员 而 Python 的 dict 是无序的集合无法通过下标访问但我们可以通过 dict 的键key来访问key 就类似于有序集合的下标。dict 的定义dict 是 Python 内置的数据类型在其它语言中一般属于非内置类型是由第三方库或者程序员本身写的库 比如 c 中的 stl 库中的 map 和 Python 的 dict 类似但实现方式不一样c 的 map 用的是红黑树Python 用的是哈希表Python 语言用 {} 来表示是一个 dict每个成员是一个键-值key-value配对。student_dict{name:ruhua,age:18}print(student_dict)dict 成员在内存中的顺序和定义时候的顺序不一定一样这是由创建哈希表的算法大家可自行搜索哈希表算法 决定的哈希表的算法决定键的存放位置。student_dict{a:1,b:2,c:3}# 内存中顺序为 {a: 1, c: 3, b: 2}print(student_dict)#注意在 Python3.8 中 print 是按照用户创建 dict 的顺序输出而不是内存顺序输出dict 的增删改查我们知道 dict 是无序的所以无法通过下标访问值但我们可以通过 key 来访问该 key 对应的值 访问方式为 dict[key]但要确保 key 存在不然会报异常我们也可以使用 dict 的 get 函数获取 key 对应的值如果 key 不存在则返回 None。mydict{a:1,b:2,c:3}print(mydict[b])print(mydict.get(b))print(mydict[d])# 报异常print(mydict.get(d))# 返回 None我们如果想给字典添加一个值可以直接通过dict[key] value的方式如果 key 已经存在的话则是修改。mydict{a:1,b:2,c:3}mydict[d]4mydict[b]5print(mydict)因为 dict 的每个成员都是键值配对所以删除成员的时候通过键删除值整个成员就会删除掉 可以使用 Python 内置函数 del 或 dict 成员函数 pop 做删除操作注意要确保删除的键存在不然会报异常。mydict{a:1,b:2,c:3}delmydict[b]print(mydict)mydict.pop(a)print(mydict)获取 dict 键值成员的函数dict 的 keys 函数获取 dict 所有成员的键放在一个 dict_keys 类型的对象中这个对象是一个可遍历的集合我们可以通过遍历这个对象获取每一个键。mydict{a:1,b:2,c:3}allkeysmydict.keys()print(allkeys)print(type(allkeys))forkeyinallkeys:print(key)dict 的 values 函数获取 dict 所有值放在一个 dict_values 类型的对象中这个对象是一个可遍历的集合我们可以通过遍历这个对象获取每一个值。mydict{a:1,b:2,c:3}allvaluesmydict.values()print(allvalues)print(type(allvalues))forvalueinallvalues:print(value)dict 的 items 函数获取 dict 所有的成员放在一个 dict_items 类型的对象中这个对象是一个可遍历的集合我们可以通过遍历这个对象获取每一个成员。mydict{a:1,b:2,c:3}allitemsmydict.items()print(allitems)print(type(allitems))foriteminallitems:print(item)注意在 Python 2 中dict 还提供了 iter 系列函数iter_keys 函数iter_values 函数iter_items 函数来获取 dict 的键值和成员并把他们放入迭代器中而 Python2 的 keys 函数values 函数和 items 函数则把取出的值放在一个 list 中。使用 dict 注意事项dict 的键就如有序集合的索引一样dict 成员的键是不可以修改的。dict 成员的键就像索引一样是不可以重复的。mydict{a:1,b:2,c:3}mydict[b]4# 只会修改键所对应的值print(mydict)因为 Python 的 dict 数据结构是采用 hash 算法构建的hash 算法决定 key 的位置 所以 dict 成员的键是必须可以 hash 的所有的常量都是可 hash 的比如数字字符串bool值None 等等 对于 tuple 来说如果 tuple 的成员也都是可 hash 的则可以否则不行。mydict {} # 空的 dict mydict[-1.1] Hello # 数字 mydict[babye] babye # 字符串 mydict[False] welcome # bool 值 mydict[None] Python mydict[(1, (2, 3))] 老鸟python # 可哈希的 tuple mydict[[1, 2]] my god # [1, 2] 不可 hash mydict[{a: 1}] my god # {a: 1} 不可 hash mydict[(1, (2, [3,4]))] # (1, (2, [3,4]) 不可 hash对 dict 成员的 key 进行增加删除操作时dict 的 hash 表的结构就会改变 成员的存储顺序就会发生变化在遍历的时候就会出现混乱因为已经遍历过的成员有可能再次被遍历等等在循环章节我们再讲这个问题。set类型Python 中有一个数据结构叫 setset 和 dict 类似也是一组 key 的集合但不存储 value。由于 key 不能重复所以在 set 中没有重复的成员。set 定义set 的定义需要提供一个 list 作为输入集合。mysetset([1,False,老鸟python])print(myset)set 中成员的特性和 dict 成员的 key 一样必须是可以 hash 的。mysetset([1,[1,2],老鸟python])# 错误成员 [1, 2] 不可 hashprint(myset)set 中成员重复的话只有一个起作用这和 dict 的 key 一样。mysetset([1,1,老鸟python])print(myset# set([1, 老鸟python]))set 是无序的不可以通过下标访问。mysetset([1,1,老鸟python])print(myset[0])# 错误set 内部的数据结构是 hash 表所以定义完成后set 内部成员的存储顺序不一定是初始化的顺序。mysetset([a,b,c])print(myset# set([a, c, b]))set 的常用函数通过 set 提供的 add 函数可以添加成员到 set 中。mysetset([a,b,c])myset.add(d)print(myset)通过 set 提供的 remove 函数可以删除成员但如果删除的成员不存在python 会抛出异常set 还有一个 discard 函数也可以删除成员并且会自动处理异常。mysetset([a,b,c])myset.remove(b)print(myset)myset.remove(d)# 抛出异常myset.discard(d)# 不做任何处理set 的 pop 函数从集合中移除成员并返回移除的成员pop 函数删除成员是从内存中第一个成员依次删除。注意Python解释器版本不同分配内存的顺序不一定相同也有的解释器每次执行时分配的内存分配的顺序也不同。mysetset([a,b,c])print(myset)# 假定内存顺序为set([a, c, b])myset.pop()print(myset)# set([c, b])myset.pop()print(myset)# set([b])注意事项set 是无序集合所以不能通过下标访问 set 成员set 里面的成员和 dict 的 key 一样而无 dict 的 value所以 set 的成员无法通过 set[] 来获取成员。set 交集和并集运算set 可以看成数学意义上的无序和无重复元素的集合因此两个 set 可以做数学意义上的交集并集等操作。myset_oneset([1,2,3,4])myset_twoset([2,4,6,8])myset_threemyset_onemyset_two myset_fourmyset_one|myset_twoprint(myset_three# set([2, 4]))print(myset_four# set([1, 2, 3, 4, 6, 8]))容器选择原则需要按位置保存一组可变数据时使用列表需要表达固定结构时考虑元组需要通过唯一键快速查找值时使用字典只关心成员是否存在、去重或集合关系时使用集合。容器可以互相嵌套但层级过深会降低可读性此时可以考虑定义类来表达数据结构。总结列表和字典可修改元组本身不可修改但其中的可变成员仍可修改。变量指向同一个列表时一处修改会在另一处可见。用字典按键组织数据和统计频次用集合去重并计算交集、并集集合也会把相等的值视为同一成员例如True与1。可用一份含重复元素的列表实现线性时间频次统计并对列表共享引用、元组成员和集合去重分别运行小例子验证。参考资料

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询