当前位置: 首页 > news >正文

Python 的列表 list 和元组 tuple 有啥本质区别?啥时候用谁更合适?

Python 的列表 list 和元组 tuple 有啥本质区别?啥时候用谁更合适?

一句话先看结论

  • 列表 list:能改、能增删,万能“购物车”,适合会变的序列数据。
  • 元组 tuple:不能改,创建后就“锁死”,更省内存、更快读,适合固定不变的数据,比如常量配置、坐标、不可变键等。

为什么会这样?因为 tuple 不允许改动,解释器可做内存和访问优化;list 需要支持增删改,内部会额外预留空间并有更多开销。

语法与不可变性

  • 列表:用方括号 [],可以随时改元素、append、pop。
  • 元组:用圆括号 (),一旦创建不能改(改就报错 TypeError)。

示例:

# 列表:能改
fruits = ["apple", "banana"]
fruits.append("pear")       # OK
fruits[^0] = "orange"        # OK
print(fruits)               # ['orange', 'banana', 'pear']# 元组:不能改
pos = (10, 20, 30)
# pos[^0] = 99               # TypeError: 'tuple' object does not support item assignment
print(pos)                  # (10, 20, 30)

这种“不可变”带来的副作用是:只要里面的元素也都不可变,元组就能当字典的键或放进 set,因为它可哈希;列表不行。

# 元组可做 dict 的键(元素都不可变时)
prices = {("apple", "small"): 3.5, ("apple", "large"): 5.0}
print(prices[("apple", "small")])  # 3.5# 列表做键会报错
# bad = {[1, 2]: "x"}  # TypeError: unhashable type: 'list'

不可变还带来另一个好处:并发里更安全(没人能改它),也更可预测(不担心被无意修改)。

性能与内存:为什么 tuple 往往更省更快(读多改少场景)

  • 内存:相同元素下,tuple 一般比 list 占用更少内存,因为它不需要为“未来的增长”预留空间,也没有可变带来的额外管理开销。
  • 访问/迭代:tuple 往往稍快于 list,尤其“只读访问”场景,因为解释器可针对不可变对象做优化(比如更紧凑的布局、少一点边界检查等)。[2][3][1][5]
  • 但注意:很多日常小规模场景下,这种差距并不大,写业务代码不必为每一次小访问纠结,先选语义更合适的数据结构才是正解。

简单对比(不同机器数值会不同,仅示意):

import sys, timedata_list = [i for i in range(100000)]
data_tuple = tuple(data_list)print("list bytes:", sys.getsizeof(data_list))
print("tuple bytes:", sys.getsizeof(data_tuple))
# 一般会看到 tuple 更小[^1][^7][^10]# 简单迭代耗时对比(多次取平均更客观)
t0 = time.perf_counter()
s = 0
for x in data_list:s += x
t1 = time.perf_counter()s = 0
for x in data_tuple:s += x
t2 = time.perf_counter()print("list iterate:", t1 - t0)
print("tuple iterate:", t2 - t1)
# 通常 tuple 稍快或相近,尤其纯读取场景[^1][^3][^6]

为什么会更省更快?大白话解释:

  • list 是“可扩容的箱子”,需要留富余空位,随时支持 append/insert/pop,因此多点管理成本。
  • tuple 是“密封好的盒子”,大小固定,解释器一次到位分配,更紧凑,拿数据更省事。

另外,tuple 在编译层面还有一些可优化场景,比如“常量折叠”:常量元组可在编译期直接预先构建,少走些指令。

什么时候用 list,什么时候用 tuple?

  • 需要改动(增删改顺序)的序列:用 list,比如收集请求、动态队列、批量构建数据。
  • 固定不变、只读的数据:用 tuple,比如常量配置、固定坐标、RGB 颜色、数据库字段定义等。
  • 需要当 dict 的键或放入 set:用 tuple(且内部元素也要不可变)。
  • 性能敏感、读多写少且数据大:倾向 tuple,省内存、迭代稍快。
  • API 设计想表达“这是只读返回值”:返回 tuple 让调用者一看就知道不可改,更安全。

示例:配置项、坐标等固定数据用 tuple

# 常量配置
ALLOWED_ROLES = ("admin", "editor", "viewer")  # 不希望被修改[^1][^6]# 坐标 / 颜色
origin = (0.0, 0.0)
white = (255, 255, 255)# 作为字典键
edge_weights = {("A", "B"): 1.2,("B", "C"): 0.8,
}  # 键是不可变的元组,语义清晰[^6][^15]

示例:会变的数据用 list

# 任务队列(会变化)
tasks = []
tasks.append("crawl_page")
tasks.append("parse_html")
tasks.pop(0)  # 处理一个
print(tasks)

一些容易踩坑的小点

  • tuple 不可变,但“浅不可变”:如果元组里放的是可变对象,比如列表,那么列表的内容还是能改的;只是不能改“这个位置放的是谁”。
t = (1, [2, 3], 4)
t[^1].append(99)     # 可以,因为改的是内部列表的内容
print(t)            # (1, [2, 3, 99], 4)
# 但 t[^1] = [8, 9] 不行,会 TypeError
  • 想“增加一个元素”的 tuple,本质是创建了一个新 tuple,并不会原地改旧的:
t = (1, 2, 3)
t2 = t + (4,)   # 新建
print(t, "=>", t2)  # (1, 2, 3) => (1, 2, 3, 4)

进阶细节:为什么 tuple 构建/读取可能更快?

  • 不可变意味着解释器知道“大小和内容不变”,可一次性分配、更紧凑地存储,访问时开销更少;同时一些常量元组还能在编译时被折叠,减少运行期开销。
  • list 为了支持动态增长,会“过度分配”预留空位,增删时需要移动或扩容,带来额外成本;但正因如此,它对频繁变动的场景更友好。

小结式指南

  • 优先按语义选型:会变→list;不变→tuple。
  • 想要更省内存、稍快迭代、可当 dict 键/放 set,且数据确实不需要改→tuple。
  • 实际性能别猜,真有需求就用 time/perf_counter 和 sys.getsizeof 做小基准对比再决定。

参考要点基于公开资料的共识:tuple 不可变带来更好的内存紧凑与一定场景下的访问优势;list 提供灵活的增删改,是通用工作马。

http://www.dtcms.com/a/324976.html

相关文章:

  • TC39x STM(System Timer)学习记录
  • 压力测试等工具源码包编译及使用方法
  • Vulnhub doubletrouble 靶场复现 详细攻略
  • Knuth‘s TwoSum Algorithm 原理详解
  • MyBatis 核心入门:从概念到实战,一篇掌握简单增删改查
  • 【东枫科技】FR3 可扩展测试平台,适用于 6G 研究与卫星通信,高达 1.6 GHz 的带宽
  • 【自动化运维神器Ansible】playbook案例解析:Tags组件实现任务选择性执行
  • 【01】华勤技术股份有限公司——华勤C++笔试,题目记录及解析
  • Java基础-使用反射做一个简易框架
  • Python 实例属性和类属性
  • 【PyTorch】单目标检测项目
  • vulnhub-Drippingblues靶机
  • Typora结合PicGo + 使用Gitee搭建个人免费图床
  • 计算机网络---IP(互联网协议)
  • 2025年6月电子学会全国青少年软件编程等级考试(Python六级)真题及答案
  • 二叉树进阶 之 【二叉搜索树的简介与模拟实现的前提准备】
  • 【杂谈】-智能代理+可观察性:构建下一代复杂系统监控体系
  • UE5多人MOBA+GAS 41、制作一个飞弹,添加准心索敌
  • JS实现数组扁平化
  • 计算二分类误差时的常见错误及解决方案
  • ubuntu22.04+samba
  • VMware 使用 Ubuntu 一段时间后逐渐卡顿、甚至卡死的问题
  • sqli-labs-master/Less-51~Less-61
  • 解读 GPT-5:从“博士级 AI 专家”能力到 OpenAI API Key 获取与实践(提示工程→性能调优全流程)
  • MySQL自增ID与UUID的区别及其在索引分裂中的表现与优化
  • W3D引擎游戏开发----从入门到精通【23】
  • 2013年考研数学(二)真题
  • A#语言详解
  • 相比于传统的全波分析,特征模分析具有哪些优点
  • vue如何监听localstorage