我在 Python 里拷贝了一个嵌套列表,以为是独立副本,结果改副本的内层元素原列表也跟着变了,我对着浅拷贝只复制一层排查了大半天的复盘
这是一个让我对 Python 的"深拷贝 vs 浅拷贝"刻骨铭心的故事。我有个嵌套的数据结构(列表里套着列表,类似一个二维表),我想要一份独立的副本来修改,而不影响原始数据。我顺手用了切片 copy = original[:](也试过 list(original)、copy.copy()),心想"这就拷贝出一份独立的了"。可当我修改这个副本里的内层元素时,诡异的事发生了:我只改了副本,可原始的那个列表,内层的数据,也跟着一起变了!我明明拷贝了一份,为什么改副本会影响到原件?这"副本",好像只独立了一半。
我顺着"改副本影响原件"的线索深挖,才终于揭开真相,补上了我对 Python 一个最基础、却极易踩的认知漏洞:问题的核心,是我做的是"浅拷贝(shallow copy)",而它只复制了"最外层"。我一直想当然地以为,"拷贝就是把整个东西完整复制一份,从里到外都独立";可真相是:original[:] / list(original) / copy.copy() 这些,都是"浅拷贝"——它只复制了最外层那个容器(创建了一个新的外层列表),而这个新列表里装的每一个内层元素,仍然是和原列表共享的、同一个对象的引用!换句话说:外层是"新的",但内层,还是"原来那些";新旧两个外层列表,指向的是同一批内层对象。所以:当我改副本里的内层元素(比如 copy[0].append(x) 或 copy[0][1] = y)时,因为 copy[0] 和 original[0] 本就是同一个内层列表,所以原列表的内层,自然也跟着变了。(而如果我替换整个外层元素,比如 copy[0] = newList,那只动了副本的外层,原件不受影响——这也印证了"只有外层是独立的"。)我这才痛彻地明白:Python 的拷贝,有"深"和"浅"之分;浅拷贝,只复制一层,内层对象仍是共享的引用;对于嵌套的数据结构,浅拷贝得到的,不是一个"完全独立"的副本,而是一个"外层独立、内层共享"的"半成品";用它来"隔离修改",会在你改动内层时,意外地"串改"了原始数据。要得到一份真正完全独立的副本,必须用 copy.deepcopy()——它会递归地、把每一层都复制一遍,让新旧之间,再无任何共享。
故障现场:浅拷贝只复制外层,内层仍共享
我把这个"改副本影响原件"的现场,摊开给你看:
# ✗ 灾难: 浅拷贝只复制外层, 内层元素仍和原对象共享
original = [[1, 2], [3, 4]] # 嵌套列表: 外层 list, 里面装着两个内层 list
# 几种常见的"浅拷贝"(都只复制最外层):
copy1 = original[:] # 切片浅拷贝
copy2 = list(original) # list() 浅拷贝
import copy
copy3 = copy.copy(original) # copy.copy() 浅拷贝
# ✗ 改副本的"内层元素", 原对象也跟着变!
copy1[0].append(99) # 改 copy1 的第0个内层 list
print(original) # ✗ [[1, 2, 99], [3, 4]] —— 原对象的内层也变了!
copy1[1][0] = 100
print(original) # ✗ [[1, 2, 99], [100, 4]] —— 又串改了!
# 为什么? 浅拷贝只复制了"外层容器", 内层是共享引用:
# - copy1 是一个"新的外层 list"(和 original 不是同一个外层)。
# - 但 copy1[0] 和 original[0] 是"同一个内层 list"(共享引用!)。
# - 所以改 copy1[0] 的内容 = 改 original[0] 的内容。
# 验证: print(copy1[0] is original[0]) → True(同一个对象!)
# 对比: 只改"外层"(替换整个元素)不影响原件
copy1[0] = [7, 8] # 替换整个外层元素(让 copy1[0] 指向新 list)
print(original[0]) # [1, 2, 99] —— 这次原件没变(只改了副本外层指向)
# → 印证: 浅拷贝"外层独立, 内层共享"。
# 同样的坑: dict 浅拷贝
d = {"a": [1, 2]}
d2 = d.copy() # 浅拷贝
d2["a"].append(3)
print(d) # ✗ {"a": [1, 2, 3]} —— 内层 list 共享, 原 dict 也变!
# 根因: 浅拷贝(切片/list()/copy.copy/dict.copy)只复制最外层容器,
# 内层嵌套对象仍是共享引用; 改内层就串改了原对象。
看着这段"改副本却串改了原件"的代码,我才算彻底想明白了根源。问题的核心,是浅拷贝只复制了"外层容器",内层是共享引用。copy1 = original[:] 之后:copy1 是一个"新的外层 list"(和 original 不是同一个外层),但 copy1[0] 和 original[0] 是"同一个内层 list"(共享引用!);所以改 copy1[0] 的内容,就等于改 original[0] 的内容(copy1[0] is original[0] 为 True)。而只改"外层"(替换整个元素 copy1[0] = [7,8])就不影响原件——这恰恰印证了"浅拷贝外层独立、内层共享"。同样的坑也出现在 dict.copy():浅拷贝 dict 后,改内层的 list,原 dict 也跟着变。归根结底:浅拷贝(切片/list()/copy.copy/dict.copy)只复制最外层容器,内层嵌套对象仍是共享引用;改内层就串改了原对象——这,就是根源。
第一件事:搞懂深拷贝与浅拷贝
定位到根源,我必须把"深拷贝 vs 浅拷贝"从根上彻底搞清楚:
浅拷贝只复制最外层(内层共享引用); 深拷贝递归复制每一层(完全独立)
# 三个层次的"复制":
# 1. 赋值 b = a: 根本没复制! a 和 b 是同一个对象(同一引用)。
# - 改 b 就是改 a(它们是一个东西)。
# 2. 浅拷贝(shallow): 复制"最外层容器", 内层元素仍是共享引用。
# - 外层独立(新容器), 内层共享(同一批内层对象)。
# - 改内层 → 影响原对象; 替换外层元素 → 不影响。
# 3. 深拷贝(deep): 递归复制"每一层", 新旧完全独立, 无任何共享。
# - 改新对象的任何层, 都不影响原对象。
# 哪些是浅拷贝?
# - 切片 a[:]、list(a)、dict(a)、set(a)、a.copy()、copy.copy(a)。
# - 列表推导 [x for x in a](也是浅, 元素还是原引用)。
# 深拷贝怎么做?
# - copy.deepcopy(a): 递归复制所有层级。
# 关键: 只有"嵌套了可变对象"时, 深浅拷贝才有区别!
# - 扁平的、只含不可变元素的(如 [1,2,3]、["a","b"]): 浅拷贝就够(改不了内层元素本身)。
# - 嵌套了 list/dict/对象 的: 必须深拷贝才能完全隔离。
# 为什么不总是用 deepcopy?
# - deepcopy 递归复制, 慢、占内存(大结构开销大)。
# - 有循环引用时要小心(deepcopy 能处理, 但要注意)。
# - 按需选: 只含不可变 → 浅拷贝; 嵌套可变且要完全隔离 → 深拷贝。
# 关键认知: "拷贝"不是非黑即白, 要分清"复制了几层"。
# - 想隔离修改, 先问: 我的数据有嵌套的可变对象吗? 有就要 deepcopy。
# 核心: 赋值=不复制, 浅拷贝=只复制外层(内层共享), 深拷贝=递归复制全独立;
# 嵌套可变对象要完全隔离必须 deepcopy; 扁平不可变浅拷贝即可。
原理终于清晰了。有三个层次的"复制":① 赋值 b = a(根本没复制!a 和 b 是同一个对象,改 b 就是改 a);② 浅拷贝(复制"最外层容器",内层元素仍是共享引用——外层独立、内层共享;改内层影响原对象、替换外层元素不影响);③ 深拷贝(递归复制"每一层",新旧完全独立、无任何共享)。哪些是浅拷贝?切片 a[:]、list(a)、dict(a)、a.copy()、copy.copy(a)、列表推导。深拷贝用 copy.deepcopy(a)。关键:只有"嵌套了可变对象"时,深浅拷贝才有区别——扁平的、只含不可变元素的(如 [1,2,3])浅拷贝就够;嵌套了 list/dict/对象的,必须深拷贝才能完全隔离。为什么不总是用 deepcopy?它递归复制、慢、占内存(大结构开销大),有循环引用要小心;按需选——只含不可变用浅拷贝,嵌套可变且要完全隔离才用深拷贝。由此,我刻下一个关键认知:"拷贝"不是非黑即白,要分清"复制了几层";想隔离修改,先问"我的数据有嵌套的可变对象吗?有就要 deepcopy"。归根结底:赋值=不复制,浅拷贝=只复制外层(内层共享),深拷贝=递归复制全独立;嵌套可变对象要完全隔离必须 deepcopy;扁平不可变浅拷贝即可。
第二件事:正解——嵌套要完全隔离就用 deepcopy
搞懂了原理,正解就清晰了:嵌套了可变对象、且要完全隔离,就用 copy.deepcopy();扁平/只含不可变的,浅拷贝就够。
import copy
# ✓ 正解一: 嵌套结构要完全独立, 用 deepcopy(递归复制每一层)
original = [[1, 2], [3, 4]]
deep = copy.deepcopy(original) # ✓ 深拷贝, 每一层都是新的
deep[0].append(99) # 改副本内层
print(original) # ✓ [[1, 2], [3, 4]] —— 原对象纹丝不动!
print(deep[0] is original[0]) # ✓ False(不是同一个内层对象了)
# ✓ 正解二: 扁平/只含不可变元素的, 浅拷贝就够(省开销)
flat = [1, 2, 3]
c = flat[:] # ✓ 浅拷贝足矣(int 不可变, 没有"改内层"一说)
c.append(4)
print(flat) # [1, 2, 3] —— 不受影响
# ✓ 正解三: 手动重建嵌套(可控, 也避免 deepcopy 开销)
matrix = [[1, 2], [3, 4]]
rebuilt = [row[:] for row in matrix] # ✓ 对每个内层也做拷贝(两层都新)
rebuilt[0].append(99)
print(matrix) # [[1, 2], [3, 4]] —— 不受影响
# ✓ 正解四: 用不可变结构, 从根上避免"被改"
point = (1, 2) # tuple 不可变, 天然安全(没法改它)
from dataclasses import dataclass
@dataclass(frozen=True) # 不可变 dataclass
class Config:
name: str
# 决策:
# - 嵌套了 list/dict/对象 + 要完全隔离 → copy.deepcopy。
# - 扁平 + 只含不可变(数字/字符串/元组)→ 浅拷贝(切片/list())即可。
# - 性能敏感的大结构 → 手动按需重建需要拷贝的部分, 避免全量 deepcopy。
# - 能用不可变结构(tuple/frozen dataclass)→ 优先, 从根上避免误改。
# ⚠ deepcopy 的注意:
# - 慢/占内存(大结构), 别滥用; 含外部资源(文件句柄/连接)的对象别 deepcopy。
# 核心: 嵌套可变+要完全隔离用 copy.deepcopy; 扁平不可变浅拷贝即可;
# 性能敏感按需重建; 能用不可变结构就用, 从根上免去拷贝烦恼。
修复的方向,核心是"按数据结构选对拷贝深度"。正解一,嵌套结构要完全独立用 copy.deepcopy():它递归复制每一层,deep[0] 和 original[0] 不再是同一个对象,改副本内层,原对象纹丝不动。正解二,扁平/只含不可变元素的,浅拷贝就够(int 不可变,没有"改内层"一说,浅拷贝省开销)。正解三,手动重建嵌套([row[:] for row in matrix] 对每个内层也拷贝、两层都新,可控且避免 deepcopy 全量开销)。正解四,用不可变结构从根上避免"被改"(tuple 不可变天然安全、frozen dataclass 不可变)。决策上:嵌套可变+要完全隔离用 deepcopy;扁平+只含不可变用浅拷贝;性能敏感的大结构按需重建;能用不可变结构(tuple/frozen)就优先用。(注意:deepcopy 慢/占内存,别滥用;含文件句柄/连接等外部资源的对象别 deepcopy。)归根结底:嵌套可变+要完全隔离用 copy.deepcopy;扁平不可变浅拷贝即可;性能敏感按需重建;能用不可变结构就用,从根上免去拷贝烦恼。
第三件事:深浅拷贝在真实场景里的坑
这次踩坑后,我把深浅拷贝在真实项目里容易翻车的场景,系统梳理了一遍:
# 深浅拷贝在真实场景里的坑:
# 1. 默认配置/模板被"串改"
default_config = {"options": {"retry": 3}}
def make_config():
cfg = default_config.copy() # ✗ 浅拷贝! options 还是共享的
cfg["options"]["retry"] = 5 # ✗ 把 default_config 也改了!
return cfg
# → 之后所有用 default_config 的都被污染。要 deepcopy。
# 2. 把对象传给函数, 函数内"以为改的是副本"
def process(data):
data["items"].append(x) # ✗ 改的是调用方传进来的原对象的内层!
# → 需要隔离就在函数内 deepcopy, 或约定不修改入参。
# 3. 缓存返回了"共享的可变对象"
cache = {"users": [...]}
def get_users(): return cache["users"] # ✗ 返回的是缓存里的同一个 list!
# 调用方改了它 → 缓存被污染。→ 返回 deepcopy 或不可变副本。
# 4. 类的可变默认属性被多实例共享(类似可变默认参数)
class Box:
items = [] # ✗ 类属性! 所有实例共享同一个 list
# → 用 __init__ 里 self.items = [] (实例属性)。
# 5. 浅拷贝以为安全, 嵌套层级深了才暴露
# - data[:] 看着拷了, 但 data[0][1] 这种第二层改动会串。
# 排查技巧: 用 is 看是不是同一对象, id() 看地址。
# print(copy[0] is original[0]) # True=共享(浅), False=独立(深)。
# 核心: 深浅拷贝坑常见于 默认配置被串改、函数改了传入对象内层、
# 缓存返回共享可变对象、类可变属性共享; 要隔离就 deepcopy 或返回不可变。
原来深浅拷贝的坑,处处潜伏。默认配置/模板被串改(default_config.copy() 浅拷贝后改内层,把默认配置也污染了,之后所有人都被影响——要 deepcopy);把对象传给函数、函数改了它的内层(改的是调用方的原对象,需要隔离就在函数内 deepcopy);缓存返回了共享的可变对象(get_users() 返回缓存里的同一个 list,调用方一改缓存就被污染——返回 deepcopy 或不可变副本);类的可变默认属性被多实例共享(items = [] 是类属性、所有实例共享,要在 __init__ 里设实例属性);浅拷贝在层级深了才暴露。排查技巧:用 is 看是不是同一对象、id() 看地址(copy[0] is original[0] 为 True 就是共享)。它们的共同根源,都是"以为拷了独立副本、实则内层还共享"。归根结底:深浅拷贝坑常见于默认配置被串改、函数改了传入对象内层、缓存返回共享可变对象、类可变属性共享;要隔离就 deepcopy 或返回不可变。
下面这张图,是这次"改副本影响原件"的成因与解法:
第四件事:赋值、浅拷贝、深拷贝速查对照
这次踩坑后,我把赋值、浅拷贝、深拷贝的区别,整理成一张速查表,以后拷贝前心里就有数了。
| 方式 | 复制了什么 | 改外层影响原件? | 改内层影响原件? |
|---|---|---|---|
| b = a(赋值) | 什么都没复制(同一对象) | ✗ 影响(就是同一个) | ✗ 影响 |
| a[:] / list(a)(浅) | 最外层容器 | ✓ 不影响 | ✗ 影响(内层共享) |
| copy.copy(a)(浅) | 最外层容器 | ✓ 不影响 | ✗ 影响 |
| copy.deepcopy(a)(深) | 递归每一层 | ✓ 不影响 | ✓ 不影响 |
| [row[:] for row in a](手动两层) | 外层+一层内层 | ✓ 不影响 | ✓ 不影响(仅限两层) |
这张表,把三种"复制"的差别讲透了。关键看最后两列——"改外层"和"改内层"是否影响原件:赋值两者都影响(根本是同一个);浅拷贝"改外层不影响、改内层影响"(外层独立、内层共享,这正是本文的坑);深拷贝两者都不影响(完全独立)。记住这个区分的实用价值:你能一眼判断"我这次拷贝,改了之后会不会串到原件"——只改外层?浅拷贝够;要改内层、且不想影响原件?必须深拷贝(或手动重建到对应层)。它给我的启发是:"拷贝"这个看似简单的操作,其实有"复制几层"的深度维度;而 Python(以及很多语言)默认提供的拷贝,往往是"浅"的——它不会替你递归到底,需要深拷贝时,你得显式地要求(deepcopy)。理解了"拷贝有深浅",并养成"拷贝嵌套结构前,先想清楚要拷几层"的习惯,就能避开这一整类"改了副本却串改原件"的隐蔽 bug。
第五件事:这些"共享可变状态"的坑同根同源
这次浅拷贝的坑,本质是"意外地共享了可变状态"。顺着这个本质,我把 Python 里其他同源的坑梳理了一遍。
| 坑 | 意外共享了什么 | 正解 |
|---|---|---|
| 浅拷贝嵌套结构 | 内层对象被新旧容器共享 | deepcopy / 手动重建(本文) |
| 可变默认参数 def f(x=[]) | 默认 list 被多次调用共享 | 默认 None, 函数内再建 |
| [[0]*3]*3 建二维 | 三行是同一个 list | [[0]*3 for _ in range(3)] |
| 类可变属性(类级 list) | 所有实例共享同一个 | __init__ 里设实例属性 |
| b = a 赋值"复制" | b 和 a 是同一对象 | 需要副本就 copy/deepcopy |
| 函数返回内部可变对象 | 调用方拿到的能改到内部 | 返回拷贝或不可变 |
这张表,让我看清了这些坑共同的根。它们本质上是同一个问题:你以为有了几个"独立"的东西,实际它们却共享着同一个可变对象;于是改其中一个,意外地"串改"了其他的。无论是浅拷贝(内层共享)、可变默认参数(默认对象共享)、[[0]*3]*3(三行共享)、类可变属性(实例共享)、赋值(同一对象)、函数返回内部可变对象(内外共享)——它们的病根,都是"在你以为是独立副本的地方,其实是共享引用";它们的解药,也都指向同一件事:当你需要"独立"时,就要显式地、彻底地创建一份新的(deepcopy/重建/返回不可变),而不能依赖"看起来像复制"的操作。它给我的最大启发是:Python(以及很多语言)里,"引用共享"是默认,"独立副本"才需要你主动争取;而"意外的共享可变状态",是一整类极其隐蔽 bug 的总源头——它不报错,只是悄悄地让"改 A 串到 B"。所以,处理可变数据时,要时刻有一根弦:"我现在操作的,是一个'独立的副本',还是一个'和别处共享的引用'?如果我改它,会不会意外地影响到别的地方?"——这根弦绷紧了,这一整类"串改"的坑,就都能避开。
第六件事:要拷贝一个数据时,我现在会怎么决策
现在,每当我要拷贝一个数据结构,脑子里都会过一遍这张决策图——核心两问:它嵌套了可变对象吗?我要改哪一层?
这张图的灵魂,是拷贝前的两个必问。第一问:它嵌套了可变对象吗?——没有(扁平且只含不可变),浅拷贝即可;有嵌套可变,再追问第二问。第二问:我会修改内层吗?——只读不改,浅拷贝甚至直接用都行;要改内层、且不能影响原件,就需要更深的拷贝。需要深拷贝时按性能选:不敏感用 copy.deepcopy(最省心);敏感/大结构则手动重建需要拷贝的那几层。最后,两个收尾的好习惯:能用不可变结构(tuple/frozen)就用,从根上免去拷贝烦恼;否则用 is/id 验证副本确实独立。这套判断,让我拷贝数据时,不再"随手 [:] 就以为独立了"——核心始终是:看清它嵌套了几层可变对象,要改到哪层,就拷到哪层。
我立下的几条规矩
这场"改副本串改原件"的事故,换来了我写 Python 时,刻进骨子里的几条铁律:
- 浅拷贝只复制最外层,内层共享引用。切片/list()/copy.copy/dict.copy 都是浅拷贝,改内层会串改原件。
- 嵌套可变要完全隔离,用 copy.deepcopy。它递归复制每一层,新旧完全独立。
- 扁平/只含不可变的,浅拷贝就够。别滥用 deepcopy(慢、占内存);按数据结构选拷贝深度。
- 默认配置/缓存/函数入参,警惕浅拷贝串改。要隔离就 deepcopy 或返回不可变副本。
- 能用不可变结构就用。tuple、frozen dataclass 天然不会被改,从根上避免拷贝烦恼。
- 拿不准就用 is/id 验证。copy[0] is original[0] 为 True 就是共享(浅),False 才是独立(深)。
- 时刻分清"独立副本"和"共享引用"。改它前问一句:会不会意外影响到别处?
附:几行代码用 id() 看清浅拷贝的"假独立"
口说无凭。下面这几段,用 id() 和 is 亲眼看清浅拷贝"外层独立、内层共享"的真面目,跑一遍胜过千言:
import copy
original = [[1, 2], [3, 4]]
# ===== 浅拷贝: 外层新, 内层共享 =====
shallow = original[:]
print(shallow is original) # False —— 外层是新的(不同对象)
print(shallow[0] is original[0]) # True! —— 内层是同一个对象(共享!)
print(id(original[0]), id(shallow[0])) # 两个 id 相同 —— 铁证内层共享
shallow[0].append(99) # 改内层
print(original) # [[1, 2, 99], [3, 4]] —— 原件被串改!
# ===== 深拷贝: 每一层都是新的 =====
deep = copy.deepcopy(original)
print(deep is original) # False
print(deep[0] is original[0]) # False —— 内层也是新的(不共享!)
deep[0].append(999) # 改内层
print(original) # [[1, 2, 99], [3, 4]] —— 原件不受影响 ✓
# ===== 一眼看穿: is / id 是验证"独立还是共享"的探针 =====
def is_shared(a, b):
return a is b # True=同一对象(共享), False=不同对象(独立)
print("外层:", is_shared(shallow, original)) # False(浅拷贝外层独立)
print("内层:", is_shared(shallow[0], original[0])) # True(浅拷贝内层共享 → 危险!)
# 核心: 跑一遍就懂 —— 浅拷贝 shallow[0] is original[0] 为 True(共享, 改内层串原件);
# 深拷贝则全 False(完全独立)。用 is/id 当探针, 一眼看穿"假独立"。
这几段代码,把浅拷贝的"假独立",用 id 和 is 照得清清楚楚。浅拷贝那段:shallow is original 是 False(外层是新的),可 shallow[0] is original[0] 却是 True(内层是同一个对象!),两个 id 一模一样——这就铁证如山地揭示了"外层独立、内层共享";于是改 shallow[0],original 被串改了。而深拷贝那段:deep[0] is original[0] 也是 False(内层也是新的、不共享),改 deep[0],original 纹丝不动。最妙的是那个 is_shared 小工具:它把 is 变成了一个"探针",一调用就能告诉你"这两个东西,是共享的同一个,还是独立的两个"。这,正是我想用这几段代码,留给每一个写 Python 的人的最后一课:当你对"这份拷贝到底独不独立"心里没底时,别猜,用 is 和 id() 这两个"探针",把对象的真实身份查出来——copy[0] is original[0] 一打印,是共享还是独立,立刻见分晓。"引用共享"这种看不见、摸不着、却又最容易出 bug 的东西,唯有用 is/id() 把它变得"可见",你才能真正地掌控它、而不是被它暗算。
写在最后
回头看,这场由"浅拷贝"引发的、改副本却串改原件的事故,真正教给我的,是一个比"用 deepcopy"本身更深的道理:我们日常说的"复制一份",在脑海里是一个"从里到外、彻底独立"的简单、完整的概念;可在计算机的世界里,"复制"却是一个有"深度层次"的、需要精确界定"到底复制到哪一层"的概念;而我们那个"理所当然的、完整的'复制'"的直觉,和计算机里"默认只复制一层(浅)"的现实之间的落差,正是 bug 滋生的温床。我犯的错,本质是用"现实世界里复制一份文件(里外都是新的)"的朴素直觉,去套了"计算机里复制一个引用结构(默认只复制外层指针)"的技术现实。这让我深刻地领悟到:编程,常常要求我们把日常那些"模糊、笼统"的概念(复制、相等、删除、修改……),拆解、细化成计算机层面"精确、有层次"的操作;而很多 bug,就源于我们把日常的粗略概念,想当然地等同于了计算机的精确语义。所以,对那些"看似简单、人人都懂"的基础操作("复制""比较""赋值"),反而要多一份较真:去追问它在计算机里"精确地"意味着什么——复制了几层?比的是值还是引用?改的是副本还是原件?。把粗略的日常概念,翻译成精确的技术理解——这,是我用一次"浅拷贝串改"的事故,换来的、关于 Python、也关于编程严谨性的、最朴素也最深刻的领悟。如果这篇复盘,能让你在下一次拷贝嵌套结构前,先想一句"这是浅拷贝还是深拷贝、我要改的内层独立吗",那我对着那个被串改的原件熬的这大半天,就值了。
—— 别看了 · 2026