尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Python 基础速通04-Python 四大容器 list/tuple/dict/set 对比:可变性、性能、拷贝问题面试必问
2026 Python 数据类型进阶list/tuple/dict/set、引用传递与深浅拷贝全解析免费基金定投助手全功能拆解为什么你的基金定投还在亏钱因为你的工具用错了。动态平衡仓位管理8种智能定投策略引擎会自己算买卖点的定投系统-CSDN博客https://download.csdn.net/download/weitingfu/93448039?spm1001.2014.3001.5503开篇黄金 100 字你是不是遇到过这种情况明明只是b a结果改b[0]时a也跟着变了或者听说 tuple 不可变却搞不清它和 list 到底差在哪这两个问题的答案都指向同一个核心概念——可变性与引用。本篇把 list/tuple/dict/set 四种容器一次讲透再用深浅拷贝的内存图把引用传递钉死在脑子里帮你把面试基础分拿满。前置知识说明本篇要求你已掌握 P03 的 Python 基础语法变量、控制流、函数、类知道for item in lst遍历和len()取长度即可。如果你还没完全熟练也可以直接读——本篇所有代码都很短重点在现象解释而非语法细节。建议准备好 Python 环境边读边敲。本篇地图模块核心问题预计时间list动态数组怎么增删改查15 分钟tuple不可变列表有什么用10 分钟dict键值对与哈希原理15 分钟set去重与集合运算10 分钟可变 vs 不可变引用传递陷阱在哪15 分钟深浅拷贝三态差异与内存图15 分钟总计约 80 分钟。前四节偏背后两节偏懂后两节是面试高频务必多花时间。一、list动态数组Python 最常用的容器1.1 创建与基本操作list 相当于 Java 的ArrayList、C 的vector有序、可变、可存放任意类型元素Python 允许异构nums [1, 2, 3] mixed [1, hello, 3.14, True, [5, 6]] # 甚至可以嵌套 empty [] # 空列表增删改查五件套lst [1, 2, 3] lst.append(4) # 末尾添加 → [1, 2, 3, 4] lst.insert(0, 0) # 指定位置插入 → [0, 1, 2, 3, 4] lst.remove(2) # 按值删除第一个 2 → [0, 1, 3, 4] popped lst.pop() # 弹出并返回末尾元素 → popped4, lst[0, 1, 3] lst[1] 99 # 按下标修改 → [0, 99, 3] print(len(lst)) # 31.2 切片list 的灵魂切片lst[start:end:step]返回新列表遵循左闭右开约定和range一致nums [0, 1, 2, 3, 4, 5] print(nums[1:4]) # [1, 2, 3] 取下标 1 到 3 print(nums[:3]) # [0, 1, 2] 从头到下标 2 print(nums[3:]) # [3, 4, 5] 从下标 3 到尾 print(nums[::2]) # [0, 2, 4] 每隔一个取一个 print(nums[::-1]) # [5, 4, 3, 2, 1, 0] 反转列表面试小考点nums[:]是什么它是从头到尾的完整切片会返回一个新的列表——也就是 list 的浅拷贝。下面讲拷贝时你还会再见到它。1.3 常用方法速查方法作用例子lst.append(x)末尾添加lst.append(4)lst.extend(iter)批量追加lst.extend([5,6])lst.insert(i, x)指定位置插入lst.insert(0, a)lst.pop(i-1)弹出元素lst.pop()lst.remove(x)按值删除lst.remove(3)lst.sort()原地排序lst.sort()lst.reverse()原地反转lst.reverse()lst.index(x)找下标lst.index(3)x in lst成员判断3 in lst注意sort和reverse是原地修改返回None——新手常写lst lst.sort()结果得到None这是个经典错误。1.4 遍历的三种姿势fruits [苹果, 香蕉, 橙子] # 姿势一直接遍历元素最常见 for f in fruits: print(f) # 姿势二同时要下标enumerate for i, f in enumerate(fruits, start1): print(i, f) # 1 苹果 / 2 香蕉 / 3 橙子 # 姿势三只要下标不推荐除非要按 index 操作其他列表 for i in range(len(fruits)): print(i, fruits[i])最佳实践要元素就for f in lst要元素序号就for i, f in enumerate(lst)。不要写for i in range(len(...))再取lst[i]那是 C/Java 的习惯Python 有更好的写法。1.5 列表推导式预告推导式是循环 收集的一行版P03 提过这里再补一个带条件的复杂例子# 取出 1-20 中能被 3 整除的数的平方 result [x * x for x in range(1, 21) if x % 3 0] print(result) # [9, 36, 81, 144, 324]推导式还能嵌套# 生成二维坐标点 points [(x, y) for x in range(3) for y in range(3)] print(points) # [(0,0),(0,1),(0,2),(1,0),(1,1),(1,2),(2,0),(2,1),(2,2)]判断标准当循环只是为了收集结果时就用推导式循环体里有复杂逻辑或多条语句才退回普通 for 循环。1.6 list 性能注意事项list 是动态数组底层是一块连续内存。它的性能特点按下标访问 O(1)lst[5]直接算地址最快末尾增删 O(1)append/pop()平均摊还 O(1)中间增删 O(n)insert(0, x)、remove(x)要移动后面所有元素查找 O(n)in、index是线性扫描。实战建议# 错误在列表头部频繁插入每次 O(n) lst [] for i in range(100000): lst.insert(0, i) # 慢 # 正确末尾添加最后反转各 O(1)总 O(n) lst [] for i in range(100000): lst.append(i) lst.reverse()规模到十万级就要开始关心复杂度了。判断元素是否存在频繁且列表很大时考虑转 setO(1) 查找换取空间换时间。二、tuple不可变列表2.1 定义与特性tuple元组和 list 几乎一样唯一区别是不可变创建后不能增删改。写法用圆括号也可省略t (1, 2, 3) t2 1, 2, 3 # 省略括号也一样 print(t[0]) # 1可以读 # t[0] 9 # TypeError: tuple object does not support item assignment2.2 单元素元组的坑(1)不是元组是整数 1 加一个括号。要创建单元素元组必须加逗号a (1) # 这是 int b (1,) # 这才是 tuple长度 1 print(type(a)) # class int print(type(b)) # class tuple记牢口诀单元素元组靠逗号不靠括号。2.3 tuple 的三大用处用处一不可变保证。函数返回不会变的数据、配置常量用 tuple 更安全能防止误改。用处二作为 dict 的键。list 可变所以不能当键会报TypeError: unhashable type: listtuple 不可变所以可以。坐标点(x, y)当键是最典型的场景grid {} grid[(0, 0)] 起点 # tuple 当键合法用处三解包赋值。元组天然支持一口气取多个值point (3, 4) x, y point # 解包 print(x, y) # 3 4这和函数返回多值时return a, b再x, y func()是同一机制Python 里极常用。2.4 tuple 可以变吗——半真半假严格说 tuple 不可变但如果 tuple 里装的是可变对象那个对象本身可以变t ([1, 2], 3) t[0].append(99) # 修改 tuple 里的 listlist 可变 print(t) # ([1, 2, 99], 3) ← 打印变了但 t 本身没被替换这里变的是 list 对象的内容不是 tuple 的结构。面试常问“tuple 真的完全不可变吗”——答tuple 的引用列表不可变但被引用的可变对象内容可以变。2.5 namedtuple有名字的元组如果元组字段一多用下标t[0]、t[1]记不住含义可以用namedtuple带名字的元组它兼具元组的轻量和类的可读性from collections import namedtuple Point namedtuple(Point, [x, y]) p Point(3, 4) print(p.x) # 3用字段名访问 print(p.y) # 4 print(p[0]) # 3也能按下标访问 x, y p # 还能解包namedtuple 是轻量数据对象的好选择比 dict 省内存、比 class 少样板适合一组固定字段的小数据。三、dict键值对与哈希原理3.1 创建与增删改查dict 相当于 Java 的HashMapPython 3.7 保证插入顺序d {name: 卡兹克, age: 25} d[city] 北京 # 新增 d[age] 26 # 修改 print(d[name]) # 卡兹克读取 del d[city] # 删除 print(d.get(city, 无)) # 无安全读取键不存在不报错3.2 必会方法get / setdefault / itemsget(key, default)安全读取键不存在返回默认值而不是抛KeyErrorsetdefault(key, default)键不存在则设置默认值并返回它存在则直接返回原值——“有则用之无则设之”items()同时遍历键和值。count {} word apple count[word] count.get(word, 0) 1 # 词频统计经典写法 d {a: 1, b: 2} for key, value in d.items(): print(key, value) # a 1 / b 23.3 哈希原理一句话dict 底层是哈希表把键通过哈希函数变成整数直接定位存储位置所以查找是 O(1)。代价是键必须是可哈希的——即不可变类型int/str/tuple/frozenset可变类型list/dict/set不能当键。3.4 更多常用方法方法作用例子d.keys()所有键的视图for k in d.keys():d.values()所有值list(d.values())d.items()键值对for k, v in d.items():d.update(other)合并另一个 dictd.update({x: 1})d.pop(key)删除并返回age d.pop(age)d.clear()清空d.clear()key in d键是否存在name in ddict(**kwargs)快速创建dict(name卡兹克)3.5 字典推导式与词频实战字典推导式长得像列表推导式只是外面用{}、冒号连接键值squares {x: x * x for x in range(1, 6)} print(squares) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25} # 反转字典键值互换 d {a: 1, b: 2} reversed_d {v: k for k, v in d.items()} print(reversed_d) # {1: a, 2: b}词频统计是 dict 最经典的应用完整流程text the quick brown fox jumps over the lazy dog the fox words text.split() freq {} for w in words: freq[w] freq.get(w, 0) 1 # 按出现次数从高到低排序 for w, c in sorted(freq.items(), keylambda item: item[1], reverseTrue): print(w, c)freq.get(w, 0) 1这一行是词频统计的万能公式背下来笔试面试都会用到。3.6 两个实战利器defaultdict 与 Countercollections模块提供了两个 dict 的强化版写真实项目时几乎天天见defaultdict给缺失键提供默认值from collections import defaultdict # 按首字母分组单词 groups defaultdict(list) words [apple, banana, avocado, cherry] for w in words: groups[w[0]].append(w) print(groups[a]) # [apple, avocado] print(groups[z]) # [] ← 不报错直接给默认空列表对比普通 dict用setdefault也能实现但更啰嗦。defaultdict 把缺键处理下沉到了容器本身代码更干净。Counter一行搞定词频统计from collections import Counter c Counter(aabbccc) print(c) # Counter({c: 3, a: 2, b: 2}) print(c.most_common(2)) # [(c, 3), (a, 2)] 出现最多的前两个Counter 本质就是 dict键→次数还额外提供most_common()、/-合并运算是统计类任务的最终答案。面试写词频统计时背手写版get公式证明基础扎实实际工程里直接用 Counter 提高效率。3.7 dict 的顺序性一个历史问题很多人有旧印象dict 是无序的——在 Python 3.6 之前确实如此。但从 Python 3.7 起作为语言规范dict 保持插入顺序d {} d[first] 1 d[second] 2 d[third] 3 print(list(d.keys())) # [first, second, third] 插入顺序 # 覆盖旧值不改变顺序 d[first] 100 print(list(d.keys())) # [first, second, third] 仍是原顺序这个特性让 dict 在很多场景下可以直接当有序结构用。但要注意set仍然是无序的别把 dict 的顺序性想当然套到 set 上。四、set去重与集合运算4.1 创建与去重set 是无顺序、不重复的集合同样基于哈希成员判断 O(1)。最常用场景是去重nums [1, 2, 2, 3, 3, 3] unique set(nums) print(unique) # {1, 2, 3} print(list(unique)) # [1, 2, 3]再转回列表4.2 集合运算set 天然支持数学里的交、并、差a {1, 2, 3, 4} b {3, 4, 5, 6} print(a b) # {3, 4} 交集a 和 b 共有 print(a | b) # {1,2,3,4,5,6} 并集全部合并去重 print(a - b) # {1, 2} 差集a 有 b 没有 print(a ^ b) # {1,2,5,6} 对称差去掉共有成员判断print(3 in a) # TrueO(1) 级别对比 list 的in是 O(n)数据量大时 set 优势明显。4.3 set 的常用方法与修改操作s {1, 2, 3} s.add(4) # 添加 → {1, 2, 3, 4} s.add(4) # 已存在无变化set 自动去重 s.discard(99) # 删除不存在的元素不报错remove 会报 KeyError s.update([5, 6]) # 批量添加 → {1,2,3,4,5,6} s.pop() # 随机弹出一个set 无序别依赖这个顺序 s.clear() # 清空discard和remove的区别remove删除不存在的元素抛KeyErrordiscard静默跳过。批量处理时优先用discard避免异常打断流程。4.4 frozenset可哈希的 setset 可变所以不可哈希不能当 dict 键frozenset是 set 的不可变版本可哈希可以当键s frozenset([1, 2, 3]) d {s: 元数据} # frozenset 当键合法 print(d[s]) # 元数据frozenset 平时用得少面试题偶尔考到set 能不能当 dict 键记住答案是不能但 frozenset 可以即可。4.5 什么时候用 set、什么时候用 list简单决策需要顺序/重复/按下标访问 → list只需要有没有→ set需要键值映射 → dict。set 和 dict 一样基于哈希所以元素也必须是可哈希的。4.6 set 实战求共同好友set 的集合运算在真实项目里最常见的应用之一就是求交集——比如找两个用户的共同好友my_friends {小明, 小红, 小刚, 小丽} other_friends {小红, 小刚, 小强} common my_friends other_friends print(common) # {小红, 小刚} 共同好友 all_friends my_friends | other_friends print(len(all_friends)) # 5 全部好友去重后数量 # 只有我有、他没有的好友 only_mine my_friends - other_friends print(only_mine) # {小明, 小丽}如果数据源是数据库或接口返回的列表先转 set 再做运算代码会非常干净liked_posts [101, 102, 103, 104] bookmarked [102, 104, 105] print(set(liked_posts) set(bookmarked)) # {102, 104} 又点赞又收藏的五、可变 vs 不可变引用传递陷阱5.1 一张表看懂四种容器的可变性容器是否可变是否有序是否可哈希查找性能典型场景list可变有序否O(n)动态数组、保持顺序tuple不可变有序是O(n)常量数据、dict 键dict可变插入序否键除外O(1)键值映射set可变无序否O(1)去重、集合运算记忆口诀可变不可变看能不能原地改可哈希不可哈希看能不能当 dict 键两者直接相关——可变类型一律不可哈希。5.2b a到底复制了什么这是本篇开篇问题的答案b a只是让b和a指向同一个对象没有复制任何数据。a [1, 2, 3] b a # b 和 a 指向同一个列表 b.append(4) print(a) # [1, 2, 3, 4] ← a 也变了为什么 list 会这样而整数不会x 5 y x # y 和 x 都指向 5 y 6 # 重新绑定 yx 还是 5 print(x) # 5区别在于list 是可变对象b.append(4)是原地修改整数是不可变对象y 6是重新绑定变量名。对不可变对象任何修改操作实际都是创建新对象然后重新绑定所以另一个变量不受影响。一句话总结可变对象共享修改不可变对象各自隔离。5.3isvs身份与值比较值内容相等is比较身份是不是同一个对象内存地址相同。a [1, 2, 3] b [1, 2, 3] print(a b) # True内容相同 print(a is b) # False是两个不同的对象 c a print(a is c) # True同一对象面试经典题为什么256 256且256 is 256都为 True但257 is 257可能是 False因为 Python 对小整数-5 到 256做了缓存优化257没有缓存每次创建新对象。这道题考的就是is的本质——身份比较。5.4 函数默认参数的可变陷阱坑 1 详解最经典的 Python 坑之一def add_item(item, lst[]): # 默认参数是可变对象 lst.append(item) return lst print(add_item(1)) # [1] print(add_item(2)) # [1, 2] ← 竟然不是 [2] print(add_item(3)) # [1, 2, 3]原因默认参数在函数定义时只计算一次所有调用共享同一个默认列表前一次的 append 会残留。解决用None哨兵函数内再创建新列表def add_item(item, lstNone): if lst is None: lst [] lst.append(item) return lst5.5 传可变对象进函数入参也会被改默认参数坑是函数外引用串扰还有一个更隐蔽的把可变对象传给函数函数内原地修改会直接影响外面的变量。def add_one_to_all(nums): for i in range(len(nums)): nums[i] 1 return nums data [1, 2, 3] result add_one_to_all(data) print(result) # [2, 3, 4] print(data) # [2, 3, 4] ← 原列表也被改了这不是 bug是 Python 的引用传递特性。如果你不希望外部数据被污染有两个选择# 方案一函数内先拷贝 def add_one_safe(nums): nums nums[:] # 浅拷贝 for i in range(len(nums)): nums[i] 1 return nums # 方案二用列表推导式生成新列表 def add_one_clean(nums): return [n 1 for n in nums]经验法则函数如果必须修改入参就明确修改如果只是基于入参算新结果一定要先拷贝或生成新对象别让副作用悄悄扩散。5.6 给 AI 写代码时的自查清单现在大家都会让 AI 帮忙写代码但 AI 最容易在可变性上翻车。给你三句自查口令每次拿到 AI 的代码先过一遍看到 另一个变量问一句“这是在拷贝还是引用”如果后面跟着append/sort/原地修改八成是引用可能污染原数据。看到函数默认参数是[]或{}直接要求 AI 改成None哨兵写法。这是 AI 高频错误。看到deepcopy问一句“有必要吗”大对象深拷贝可能拖慢整个程序优先考虑浅拷贝或直接引用。这三条解决 90% 的可变性相关 bug。其他内容让 AI 随意发挥但可变性这关必须人盯。5.7 一个生活化比喻白板与便利贴把变量名想象成标签把对象想象成东西不可变对象int/str/tuple像便利贴你改不了便利贴上的内容要改就撕下来换一张新的。所以y 6只是给y贴上新的便利贴x手里的旧便利贴纹丝不动。可变对象list/dict/set像白板你可以往白板上写内容。b a相当于两个人看同一块白板任何人写字另一个人都看得见——这就是引用传递的根源。浅拷贝像复印白板的清单复印出来的是一张写着白板上所有东西的清单但清单指向的还是原来的白板。深拷贝像搬来一块新白板并抄一遍彻底独立互不影响。以后遇到为什么它变了的诡异问题先在脑子里画这个比喻再对照代码找是谁在改白板。六、深浅拷贝赋值/浅拷贝/深拷贝三态6.1 三个层次的拷贝拷贝前先明确三种操作操作行为效果b a赋值只是引用完全不复制两个名字一个对象b a.copy()/b a[:]浅拷贝新建外层对象但子对象仍共享b copy.deepcopy(a)深拷贝新建外层对象 递归复制所有子对象6.2 浅拷贝的内存图import copy a [[1, 2], [3, 4]] b a.copy() # 浅拷贝外层新列表内部两个小列表仍共享 b[0].append(99) # 修改共享的子列表 print(a) # [[1, 2, 99], [3, 4]] ← a 也变了 b[1] [0, 0] # 替换 b 的第二个子列表只动 b print(a) # [[1, 2, 99], [3, 4]] ← a 不受影响内存指向示意浅拷贝内存图b a.copy() a ──► [外层列表A] ──► [子列表1] ←──┐ │ │ 共享 b ──► [外层列表B] ──► [子列表1] ←──┘ └──► [子列表2] 共享图注浅拷贝只新建了外层列表内层子列表 a 和 b 仍指向同一对象所以通过 b 修改子列表会波及 a。6.3 深拷贝完全隔离import copy a [[1, 2], [3, 4]] b copy.deepcopy(a) # 深拷贝所有层都新建 b[0].append(99) print(a) # [[1, 2], [3, 4]] ← a 完全不受影响 print(b) # [[1, 2, 99], [3, 4]]深拷贝内存指向示意深拷贝内存图b copy.deepcopy(a) a ──► [外层A] ──► [子列表1] b ──► [外层B] ──► [新子列表1] │ │ └──► [子列表2] └──► [新子列表2] 全部独立互不共享图注深拷贝递归复制每一层a 和 b 完全隔离改任何一方都不影响另一方。6.4 三态对比总结场景用哪个为什么只想要第二个名字赋值b a零开销外层独立、内层共享即可浅拷贝a.copy()快适合一层结构完全独立、不许互扰深拷贝deepcopy慢但彻底只想复制一小段切片a[:]即浅拷贝深拷贝性能开销大递归复制所有子对象嵌套很深或元素很多时非常慢。所以坑 5 提醒大数据慎用深拷贝先想清楚真的需要完全隔离吗很多时候浅拷贝就够。6.5 拷贝在 dict 和自定义对象上的应用拷贝不仅适用于 listdict 也一样d1 {a: [1, 2], b: 3} d2 d1.copy() # 浅拷贝 d2[a].append(99) # 改共享子列表 print(d1) # {a: [1, 2, 99], b: 3} ← 受影响 d3 copy.deepcopy(d1) # 深拷贝 d3[a].append(100) print(d1) # {a: [1, 2, 99], b: 3} ← 不受影响自定义类也一样deepcopy能递归复制类实例的内部状态。但要注意包含文件句柄、数据库连接、网络 socket 的对象不能深拷贝会复制出无意义的连接这类对象应自行实现__deepcopy__控制行为或者干脆避免拷贝。6.6 拷贝速查三个问题面试官常从这三个角度连环问拷贝问 1a b[:]是什么拷贝浅拷贝。外层独立子对象共享。问 2深浅拷贝的区别一句话怎么说深拷贝递归复制所有层浅拷贝只复制最外层。问 3什么时候必须深拷贝嵌套结构需要完全隔离时比如把配置模板复制成多份互不影响的实例数据。七、常见坑5 条高频翻车记录坑 1函数默认参数用可变对象 → 状态串扰。前面 5.4 已详解。解决用None哨兵函数内再lst []。坑 2a b当拷贝用 → 数据互改。复制 list 请用a.copy()、a[:]或list(a)不要a b。注意a b[:]是浅拷贝嵌套结构仍共享。坑 3把 list 当 dict 键 →TypeError: unhashable type: list。list 可变不可哈希。解决转 tuple如d[tuple(lst)] 1。坑 4tuple(1)报错 → 需要tuple([1])或(1,)。tuple(1)会报TypeError: int object is not iterable因为 tuple() 接收可迭代对象。单元素元组直接写(1,)。坑 5深拷贝性能开销大 → 大数据慎用。一个包含 10 万行数据的嵌套结构deepcopy可能耗时数秒。解决评估是否真的需要全量隔离能浅拷贝就别深拷贝能用引用就别复制。坑 6list(d.keys())忘记转 list → 拿到视图而非列表。d.keys()返回的是动态视图随 dict 变化而变化且不能直接按下标访问。要定格成列表必须list(d.keys())。面试若问keys() 返回什么答视图 view是加分项。坑 7a b.sort()拿不到排序结果 →sort返回 None。sort/reverse原地修改并返回Nonesorted(b)才返回新列表。记口诀sort改自己sorted出新货。7.1 常见疑问集中答疑6 问问 1什么时候用 tuple 而不是 list答三个场景——①数据不该变配置、常量、函数返回的固定结果②要当 dict 键或放 set 里需要可哈希③对性能有极致要求tuple 比 list 略省内存、创建更快。日常写代码没有强制约束但如果一个列表你从没增删改过它用 tuple 更符合语义、也更安全。问 2dict 和 set 都是大括号{}到底是空 dict 还是空 set答是空 dict。空 set 必须写set()。因为 dict 使用太普遍Python 把{}默认给了 dict这个面试常考忘一次正常记住就再也不错了。问 3d.get(k)和d[k]有什么区别答d[k]键不存在抛KeyErrord.get(k)返回None可传默认值d.get(k, 0)。想要出错时快速暴露问题用d[k]想要安全兜底用get。统计场景几乎必用get。问 4浅拷贝之后改 a 的元素 b 会变吗反过来呢答要分两层看。外层改a[0] xxx不会影响 b外层独立内层改a[0][0]会影响 b子对象共享。所以会不会互相影响永远要问改的是哪一层。问 5为什么可变对象不能当 dict 键答dict 靠哈希定位。如果键可变它哈希后存进去了之后你改了它哈希值变了dict 就再也找不到它了会变成幽灵键。Python 为了避免这种状态混乱直接禁止可变类型当键。问 6set 和 dict 查找都是 O(1)为什么有的程序还是慢答哈希查找本身快但哈希函数计算、内存寻址、冲突处理都有开销。数据量很小时几十个元素list 的线性查找反而可能更快常数更小。所以选数据结构要看数据规模和读写比例不要迷信 O(1)。问 7写完发现数据被莫名改了怎么快速定位答按三条线索查①看有没有赋值后发生原地修改引用②看函数是否传入了可变对象并原地操作③看是否用了浅拷贝共享子对象。经验上 90% 的莫名变化是这三个原因之一用 5.7 的白板比喻逐条排查即可。八、练习题/动手任务任务 1统计一段英文文本的词频dict。给一个字符串apple banana apple cherry banana apple用split()切成单词列表再用count[word] count.get(word, 0) 1统计。验收输出{apple: 3, banana: 2, cherry: 1}。任务 2实现浅拷贝 vs 深拷贝的嵌套列表对比实验。定义a [[1,2],[3,4]]分别用b a.copy()和c copy.deepcopy(a)然后对b[0]和c[0]做append(99)打印a。验收a只受b影响不受c影响并能口头解释原因。任务 3用 set 求两个列表的交集与去重。给l1 [1,2,2,3,4]、l2 [3,4,5]输出①l1去重后的列表②两列表的交集。验收分别为[1,2,3,4]和{3,4}交集可用 set 或 list。任务 4进阶验证is与的差异。创建两个内容相同的列表、两个大整数如 1000分别用和is比较并打印id()看内存地址。验收能解释为什么 list 的is为 False 而小整数缓存区间的is为 True。任务 5用 defaultdict 实现分组统计。给一个商品价格字典{苹果: 3.5, 香蕉: 2.0, 橙子: 4.2, 梨: 3.8}按价格是否超过 3 元分组为两个列表。验收输出形如{便宜: [香蕉], 贵: [苹果, 橙子, 梨]}的分组结果。任务 6综合挑战学生成绩单管理。用 dict 存 5 个学生的成绩{张三: [85, 92, 78], 李四: [88, 76, 95], 王五: [90, 90, 90]}完成①打印每个学生的平均分②找出平均分最高的学生③用 set 计算所有学生成绩的去重集合。验收能输出平均分排序和去重后的成绩集合。九、总结与下一篇预告9.1 本篇核心结论list 有序可变、tuple 不可变、dict/set 基于哈希可变性决定能不能当键哈希决定查找快不快。可变对象传递靠引用b a不复制原地修改会波及不可变对象修改即重新绑定天然隔离。拷贝分深浅赋值零拷贝、浅拷贝共享子对象、深拷贝完全隔离——按需选择深拷贝慎用。9.2 一张速查卡问题一句话答案b a复制了吗没有只是引用要复制 list 怎么办a.copy()或a[:]浅要完全隔离嵌套结构copy.deepcopy(a)list 能当 dict 键吗不能转 tuple(1)是元组吗不是(1,)才是去重最快的办法set(lst)和is的区别值 vs 身份9.3 选容器三步决策法写代码时不知道用哪个容器按下面三步走第 1 步要不要键值对应 → 要dict或 defaultdict/Counter 第 2 步要不要保持顺序/允许重复 → 要list 第 3 步只需要存在不存在/去重 → 要set 剩下数据不该变 → tuple口诀映射找 dict顺序找 list存在性找 set不变找 tuple。先定这三步再谈拷贝、性能这些进阶话题。9.4 本篇与系列的整体位置这是系列第 04 篇后面你会看到字符串与正则P05大量用到不可变对象思想文件读写P06 前后会把 dict/list 用在实际数据上。容器是 Python 的基建本篇的可变性与拷贝更是整个 Python 内存模型的基石务必练熟任务 1-6 再进入下一篇。9.5 本篇必背五句话list 有序可变tuple 不可变dict/set 哈希查找 O(1)。b a是引用不是拷贝复制用copy()/[:]彻底隔离用deepcopy。可变类型不可哈希不能当 dict 键要当键就转 tuple/frozenset。默认参数别写[]/{}用None哨兵。函数内改可变入参 改外部数据不想污染就先生成新对象。背完这五句本篇的 90% 考点已经在你兜里。剩下 10% 靠练——任务 1-6 全部跑通再去刷两道浅拷贝/深拷贝的代码阅读题本篇就算真正吃透了。记住数据结构的价值不在背表格而在写代码时选对容器、想清拷贝、防住可变性这三件事做到位你就已经超过很多工作一两年的人了。【系列文章预告】下一篇我将带你玩转字符串与正则表达式从 f-string 到 re 模块实战敬请关注。如果你觉得本篇有用点个收藏方便复习遇到为什么变了的诡异问题先想想是不是可变性在作怪。我们下一篇见。十、标签Python数据类型Python listPython tuple深浅拷贝Python set dictPython入门Python教程本文为《Python 基础速通——AI 时代的第一门课》系列第 04 篇。
RELATED

相关推荐

Deepseek Prompt管理插件:YAML驱动的声明式Prompt运维

Deepseek Prompt管理插件:YAML驱动的声明式Prompt运维

1. 项目概述:一个被戏称“牛马”的Deepseek插件,到底在解决什么实际问题?最近在几个技术社区和开发者群聊里,频繁看到“牛马的Deepseek Harness插件:dsh-agent-prompt”这个标题被转发、讨论,甚至带点自嘲式…

📅 2026/10/15 5:32:56
AI 智能体详解17-智能客服 Agent 实战拆解:AI 分流率 60%+ 与降本 72% 是怎么做到的

AI 智能体详解17-智能客服 Agent 实战拆解:AI 分流率 60%+ 与降本 72% 是怎么做到的

客服与营销 Agent:从“问答机器人”到“数字坐席” 免费基金定投助手全功能拆解:为什么你的基金定投还在亏钱?因为你的工具用错了。动态平衡仓位管理8种智能定投策略引擎,会自己算买卖点的定投系统-CSDN博客 https://download.csd…

📅 2026/10/15 5:32:56
GitLab API修改邮箱实战:权限、确认机制与避坑指南

GitLab API修改邮箱实战:权限、确认机制与避坑指南

在接到这类“API改了邮箱但没成功”的问题时,我第一反应通常是:你调用的端点对不对、权限够不够、有没有处理确认机制。GitLab的API改邮箱看着是个简单的PUT操作,实际踩进去会发现各种坑:权限不足、邮箱格式校验、主邮箱和备用邮箱…

📅 2026/10/15 5:32:56
MORE NEWS

更多资讯

📰

PyTorch核心机制与实战:从动态计算图到高效训练

前几年我第一次上手PyTorch,第一感觉就是这框架调试体验太好了:模型想改哪里就改哪里,print随手一打就能看到张量的流动,根本不用费劲脑补什么静态图。那时候我就意识到,深度学习框架的天平正在悄悄倾斜,而…

📰

Git报错‘not in a work tree’深度解析与防御指南

1. 这个报错不是Git坏了,是它在认真执行你的指令“fatal: This operation must be run in a work tree”——第一次看到这条报错时,我正急着把一个刚写完的脚本推到远程仓库,敲下git push回车后,终端突然弹出这行红字,…

📰

亲测5款降AI工具:毕业论文AI率从37%降到12%的完整方案

“AI率”这个词,这两年把研究生们折磨得不轻。去年我临近毕业那阵子,导师在群里发了个通知:毕业论文送审前,必须提交一份某学术检测系统的AIGC疑似度报告,参考标准是不超过30%。我们实验室几个同门当场有点懵&#xff…

📰

PyTorch深度学习实战:从环境配置到模型训练全指南

1. 为什么选择PyTorch:从动态图到研究首选这几年深度学习框架的格局变化大家都有目共睹。早几年TensorFlow几乎一统天下,但PyTorch凭着动态计算图这一招,硬生生在学术界和工业界杀出了一条血路。很多研究机构和知名公司的默认框架都换成了PyT…

📰

FSTN段码液晶屏为何成为户外设备首选?

在智能水表、户外工控终端、车载仪表、环境监测仪、光伏逆变器和工程机械面板中,FSTN 段码屏的出现频率越来越高。它并不是“参数最豪华”的液晶方案,却是户外固定信息显示里最容易被工程师选中的类型。核心原因只有一句话:在阳光、宽温、低功…

📰

软件工程教程课后习题答案解析与工程能力提升指南:需求分析、结构化设计与测试用例设计

简介:本资源为《软件工程教程》(第2版)(吴迪、马宏茹、丁万宁主编)的课后习题参考答案,面向高校软件工程课程学生及备考复习者,帮助解决课后练习核对与知识点梳理问题。压缩包内共1个doc文档,约1.1MB&#…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬