🧩 第五章 理解内存结构:程序员的基本素养
📄 一句话概括

浅复制只复制最外层——shallow.items 和 origin.items 是同一个列表,改一个两个都变。

📝 本节和前面几节的关系

5.9 说变量存地址,这一节说想真复制的时候会踩什么坑。

一、三种操作

y = x:只复制地址,外层内层全共用。 copy.copy(x):新建一个外壳,内层还是共用——这叫浅复制。 copy.deepcopy(x):外壳内层全新建——这叫深复制。 三者的区别只在【复制的深度】,不在对象大小。

二、实测

shallow.items.append(3) 之后 origin.items 也变成 [1, 2, 3]。 deep.items.append(4) 之后 origin.items 还是 [1, 2, 3]。 同一段代码,只因为复制方式不同,结果一个是【跟着变】一个是【不变】。

三、最常见的两个坑

默认参数:def f(items=[]) 里的那个列表只创建一次,所有调用共享。 缓存:把对象塞进缓存时不复制,之后改对象等于偷偷改了缓存。 这两个坑的共同点:你以为是新的,其实是同一个。

四、怎么判断

只问一句:内层对象要不要独立? 要独立——deepcopy;只要外壳独立——copy;都无所谓——直接赋值。 最贵的不是 deepcopy 的开销,是复制错了之后查三天。

五、动手 Demo:复制存储实例的变量时要多加注意

一个对象装着一个列表,分别浅复制和深复制一份。 改内层,看原件跟不跟着变。

import copy
origin = Bag([1, 2])
shallow = copy.copy(origin)
deep = copy.deepcopy(origin)
shallow.items.append(3)
deep.items.append(4)
print(origin.items, shallow.items, deep.items)

实跑输出:

--------------------------------------------------------------------
复制存储实例的变量时要多加注意
--------------------------------------------------------------------

  浅复制和深复制,**差在【内层对象复不复制】上。**实测:

      origin.items    [1, 2, 3]
      shallow.items   [1, 2, 3]
      deep.items      [1, 2, 4]

      改 shallow 的内层,origin 跟着变吗   变
      改 deep 的内层,origin 跟着变吗      不变

  操作              外层     内层     后果
  ---------------------------------------------------
  y = x             共用     共用     改哪都变
  copy.copy         新建     共用     改内层两个都变
  copy.deepcopy     新建     新建     互不影响

  **浅复制只复制了最外面那一层**——`shallow.items` 和 `origin.items` 是同一个列表。
  **这个坑最常在【缓存】和【参数默认值】上踩**:默认参数只算一次,所有调用共享。
  **记一条:要独立副本,先用 deepcopy;只想共享,就别复制。**

实测:浅复制跟着变(origin 也成 [1, 2, 3]),深复制不跟着变(还是 [1, 2, 3])。 浅复制只复制最外面一层——shallow.items 和 origin.items 是同一个列表。

30 秒实验

  1. 找一个带列表默认参数的函数,多调两次,看列表是不是越积越多。
  2. 把一次 copy.copy 换成 deepcopy,看行为变不变。

常见误区

  1. 以为 copy.copy 就是全部复制。它只复制最外层。
  2. 以为复制总比不复制安全。复制错了比不复制更难查。
自测三问(点开对答案) 1. 三种操作各复制了什么? —— `y = x` 只复制地址;`copy.copy` 新建外壳、内层共用;`copy.deepcopy` 外壳内层全新建。 2. 实测浅复制和深复制差在哪? —— 浅复制后改内层原件跟着变([1,2,3]);深复制不跟着变,原件还是 [1,2,3]。 3. 最常见的两个坑是什么? —— 列表默认参数(只创建一次、所有调用共享)和缓存(塞进去不复制,后来被偷偷改)。

相关笔记