当前位置: 代码网 > it编程>前端脚本>Python > 一文彻底搞懂Python列表、元组、字典从创建到底层

一文彻底搞懂Python列表、元组、字典从创建到底层

2026年08月29日 Python 我要评论
前三篇我们分别讲了常量/变量/运算符、条件与循环、函数。本篇把容器三件套——列表 list、元组 tuple、字典 dict——一次性讲透:不只是「怎么

前三篇我们分别讲了常量/变量/运算符条件与循环函数。本篇把容器三件套——列表 list、元组 tuple、字典 dict——一次性讲透:不只是「怎么用」,更讲清「为什么这么设计、底层怎么存、面试会被怎么追问」。

一、引子:为什么需要容器

写代码经常会遇到这种情况:要存一组数、一组对象,甚至数量都不确定。

num1 = 10
num2 = // ... 复制粘贴二十遍

如果数据少,多个变量也凑合;但数据一多(比如一个班级的成绩、一个接口返回的字段列表),逐个变量就崩了。你需要一种「批量装数据」的方式——这就是容器

python 里最常用三种:列表可变序列元组不可变序列字典键值映射。它们也是后面写爬虫、写后端、写数据处理绕不开的基础。

二、列表 list:可变的序列

2.1 创建与本质

a = []            # 空列表
a = list()        # 等价写法
a = [1, 2, 3, 4]
a = [1, 'hello', true]   # 元素可以是不同类型(和 c/c++ 数组差别巨大)

要点: python 的 list 不要求元素类型一致。底层其实是一个「指向对象的指针数组」(pyobject* 数组),所以能塞任意类型。这一点和 c 的 int arr[10]、c++ 的 vector<int> 都不同——后者类型固定。

2.2 下标与切片

a = [1, 2, 3, 4]
print(a[2])      # 3,下标从 0 开始
print(a[-1])     # 4,负数表示倒数第几个
print(a[1:3])    # [2, 3],前闭后开区间 [1, 3)
print(a[1:])     # [2, 3, 4],省略后边界
print(a[::-1])   # [4, 3, 2, 1],步长为负数=倒序

边界细节:

  • 下标越界会抛 indexerror,但切片越界不会报错,能取多少取多少——这和 c/c++ 完全不同,新手容易误以为切片也越界崩溃。
  • 负数步长 a[::-1] 是「不创建新逻辑、只改遍历方向」的语法糖,常用于反转列表。

2.3 增删改查

a = [1, 2, 3, 4]
a.append('hello')        # 尾插,o(1) 平均
a.insert(1, 'x')         # 指定位置插入,o(n)
print(2 in a)            # true,in 判断是否存在
print(a.index(2))        # 1,找不到抛 valueerror
a.pop()                  # 删末尾,o(1)
a.pop(2)                 # 按下标删,o(n)
a.remove(2)              # 按值删,o(n)(先找后删)

方法 vs 函数: append 是「方法」——它依附于 a 这个对象(a.append),不是独立函数。这是面向对象「消息发送」的写法,和之前学的独立函数 len(a) 不同。

2.4 连接

a = [1, 2, 3, 4]
b = [5, 6, 7]
print(a + b)             # 新列表 [1,2,3,4,5,6,7],a/b 不变
a.extend(b)              # 把 b 拼到 a 末尾,修改 a,不改 b

+ 生成新对象,extend 原地修改——这是「要新列表还是改原列表」的关键取舍。

2.5 面试官会怎么考

  1. append 和 insert 复杂度为什么差这么多? 答:list 是动态数组,尾插只需在末尾放元素;insert(i) 要把 i 之后的元素整体后移,最坏 o(n)。
  2. remove 和 pop 哪个快? pop() 删末尾 o(1),pop(i)/remove 都要搬移,o(n)。
  3. 切片是深拷贝还是浅拷贝? 切片(如 a[:])创建新列表,但元素是「引用拷贝」——元素是对象时,新旧列表指向同一批对象(浅拷贝)。这是经典坑,后续讲深拷贝再展开。

三、元组 tuple:不可变的序列

3.1 创建与不可变

t = ()
t = tuple()
t = (10, 20)
def getpoint():
    return 10, 20      # 实际上返回的就是元组
result = getpoint()
print(type(result))    # <class 'tuple'>

为什么有了列表还要元组? 两个核心原因:

  1. 安全: 把数据交给一个函数处理,你不确定它会不会把你的数据弄乱。传元组,对方改不了,安心。
  2. 能当字典的键: 字典的键必须是「可哈希(不可变)」的对象,列表不行,元组可以。

3.2 支持的操作

元组支持读操作:下标、切片、遍历、inindex+不支持写操作:不能改元素、不能增删、extend 也没有。

t = (1, 2, 3, 4)
print(t[0], t[1:3], 2 in t)   # 这些都能用
# t[0] = 100                  # 报错:元组不可修改

3.3 面试官会怎么考

  • 「函数为什么会返回元组?」 答:python 用逗号 , 打包返回多个值,本质就是元组;用 a, b = f() 解包,或 _ 忽略不想要的返回值(如 _, b = getpoint())。
  • 「元组和列表怎么选?」 数据不需要变 → 优先元组(安全、可作 key);需要增删改 → 列表。

四、字典 dict:键值对映射

4.1 创建与本质

d = {}
d = dict()
student = {'id': 1, 'name': 'zhangsan'}
student = {
    'id': 1,        # 末尾逗号可写可不写
    'name': 'zhangsan'
}

字典的本质是哈希表(hash table)。键 key 和值 value 一一映射,靠 key 快速查 value——类比「学号→学生」。

4.2 查 / 增 / 改 / 删

print('id' in student)     # true
print(student['id'])       # 1,key 不存在抛 keyerror
student['score'] = 90      # key 不存在→新增;存在→修改
student.pop('score')       # 按 key 删

要点: student['score'] = ... 这行既是新增也是修改,「存在就看赋值、不存在就插入」,记住这一个规则即可。

4.3 遍历

for key in student:            # 直接遍历拿到 key
    print(key, student[key])

print(student.keys())          # dict_keys,拿到所有 key
print(student.values())        # dict_values,拿到所有 value
print(student.items())         # dict_items,拿到所有 (key, value)

️4.4合法的 key 类型

print(hash(0))          # 能算哈希 → 可作 key
print(hash('hello'))
print(hash(()))         # 空元组也能算哈希
# print(hash([1, 2, 3]))   # 报错:列表不可哈希
# print(hash({'id': 1}))   # 报错:字典也不可哈希

为什么限制 key 必须是可哈希? 哈希表靠 hash(key) 定位桶位,如果 key 能变,定位就失效了。所以「可变对象(list、dict)」统统不能当 key,而「不可变对象(int、str、tuple)」可以。

4.5 面试官会怎么考

  • 「dict 查找是 o(1) 吗?」 答:平均 o(1),但哈希冲突严重时退化;最坏情况(全冲突)理论 o(n),工程中靠扩容和好哈希规避。
  • 「list 和 dict 都能存多个数据,怎么选? 答:要「按位置取」用 list;要「按名字/id 取」用 dict。dict 的语义是映射,list 的语义是序列。
  • 「哈希冲突怎么办?」 答:开放寻址或链地址;python 用开放寻址,负载因子超阈值就 rehash(重建表),这也解释了为什么 dict 频繁插入会偶发卡顿。

五、三者横向对比(一张表看懂)

维度列表 list元组 tuple字典 dict
可变性可变(能增删改)不可变键值可变,但 key 必须不可变
底层动态数组不可变数组哈希表
典型用途未知数量、需修改的序列固定数据、函数多返回值、作 key按 key 快速查值
下标/切片支持支持不支持(用 key 取)
能否作 dict key不能不能
查找复杂度o(n)(in)/ o(1)(下标)同左平均 o(1)(按 key)

一句话选型: 需要改 → 列表;固定不变 → 元组;要按名字查 → 字典。

六、常见陷阱与误区

  1. 切片越界不报错a[100:200] 越界只取能取的,新手常以为会崩——和 a[100] 下标越界抛异常不同,别混。
  2. 方法 vs 函数a.append(x) 是方法(依附对象),len(a) 是函数(独立)。概念不清会导致「为什么有的有括号有的没有」的困惑。
  3. 元组「不可变」的边界:元组里的元素不能换,但如果元素本身是可变对象(如 list),元素内部仍可改——元组只保证「指向不变」,不保证「内容不变」。
  4. + 与 extend 的副作用+ 不改原列表,extend 改原列表,写并发/共享数据时要小心。

七、小结 & 下一步

列表、元组、字典是 python 日常最高频的三种容器:

  • 列表是「可变的动态数组」,下标/切片/增删改查全套,记住尾部操作的复杂度差异;
  • 元组是「不可变的序列」,安全、能作字典键、天然适合多返回值;
  • 字典是「哈希表」,围绕 key 做映射,key 必须可哈希。

这三者和前三篇的函数、循环配合起来,就能写出真正有结构的程序——比如用 dict 存学生信息、用 list 收集结果、用 tuple 返回多值。下一阶段建议往两个方向走:一是字符串与文件操作(把数据真正落地),二是面向对象与类(理解「方法」背后的对象模型)。先把这三件套练熟,后面学 pandas、写后端都不虚。

到此这篇关于python列表、元组、字典从创建到底层的文章就介绍到这了,更多相关python列表、元组、字典内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com