Python 关于浅拷贝的进一步思考(以 list 为例)

本文详细探讨了Python中的浅拷贝机制,以列表为例,说明了浅拷贝下变量共享内存的情况。通过实例展示了浅拷贝对值和地址的影响,以及del语句对浅拷贝的处理,强调了Python中对象引用的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Python 关于浅拷贝的进一步思考(以 list 为例)

浅拷贝

Python 中的浅拷贝是指,多个变量共用一块内存存储数据。当一个变量对其进行修改时,其他变量的值也会进行修改。例如:

1. 我们先创建两个列表 a 和 b

a = [1,2,3]
b = [10, a]
print("初始化状态:")
print("a id:", id(a))
print("b id:", id(b))
print("a:", a)
print("b:", b)

输出结果为:

初始化状态:
a id: 2017213931272
b id: 2017213129032
a: [1, 2, 3]
b: [10, [1, 2, 3]]

2. 修改 a 的值(观察浅拷贝对值的影响)

a.append(4)
print("修改 a 的值:")
print("a id:", id(a))
print("b id:", id(b))
print("a:", a)
print("b:", b)

输出结果为:

修改 a 的值:
a id: 2017213931272
b id: 2017213129032
a: [1, 2, 3, 4]
b: [10, [1, 2, 3, 4]]

对 a 进行追加后 b 也发生了修改。这是因为 b 中的 a 值,其实是对 a 的一个浅拷贝(也可以看作是引用),这个过程并没有创建一个新的副本。因此,a 的修改会直接影响 b 的修改。 由于 a 和 b 都没有创建新的副本,所以 a 和 b 的地址均没有发生变化。

3. 创建 a 的一个浅拷贝(观察浅拷贝对地址的影响)

print("创建 a 的一个浅拷贝:")
c = a
print("a id:", id(a))
print("c id:", id(c))
print("a:", a)
print("c:", c)

输出结果为:

创建 a 的一个浅拷贝:
a id: 2017213931272
c id: 2017213931272
a: [1, 2, 3, 4]
c: [1, 2, 3, 4]

新创建的变量 c 和 变量 a 的值和地址一样。这是因为 c 是 a 的一个浅拷贝,他们共享一块内存地址,这也是为什么修改一个变量会影响另一个变量值。当然也可以将 c 理解为 a 的一个别名(或者看作是引用)

  1. 对 a 进行重新赋值
print("对 a 进行重新赋值:")
a = [9, 8, 7]
print("a id:", id(a))
print("b id:", id(b))
print("c id:", id(c))
print("a:", a)
print("b:", b)
print("c:", c)

输出结果为:

对 a 进行重新赋值:
a id: 2017213165000
b id: 2017213129032
c id: 2017213931272
a: [9, 8, 7]
b: [10, [1, 2, 3, 4]]
c: [1, 2, 3, 4]

在这里可以观察到以下特点:
\quad 1. a 和 c 的值和地址均不相同。
\quad 2. a 重新赋值后不再影响 b 和 c 的值。
我们可以这样理解这个过程:
首先,创建了一个列表 a (id 为 2017213931272),然后列表 b (id 为 2017213129032) 引用了列表 a 并将其作为 b 的一部分。因此,当 a 被修改时,b 也会被修改。
然后,创建了一个列表 c (id 为 2017213931272),由于 c 的创建是通过 c=a 创建的,所以 c 是 a 的一个浅拷贝。因此,c 和 a 的地址和值均相同。
最后,当我们对 a 进行重新赋值时,系统会从内存中调出一个新区域存放我们的数据。而不是在原来的地址处重新复写,这解释了为什么 a 和 c 的地址和数据均不相同。 由于这里的 a 会重新分配一块内存,所以 a 也没有办法影响 b 原来引用 a 那部分的值。(此时的 a 已经不是原来的那个 a了)

  1. 讨论 del 对浅拷贝的影响
a = [1,2,3]
b = [10, a]
c = a
print("初始化状态:")
print("a id:", id(a))
print("b id:", id(b))
print("b[1] id:", id(b[1]))
print("c id:", id(c))
print("a:", a)
print("b:", b)
print("c:", c)
print()

# 删除 a
del a
print("删除 a 后的状态:")
print("b id:", id(b))
print("b[1] id:", id(b[1]))
print("c id:", id(c))
print("b:", b)
print("c:", c)

输出结果为:

初始化状态:
a id: 2017213145928
b id: 2017213039816
b[1] id: 2017213145928
c id: 2017213145928
a: [1, 2, 3]
b: [10, [1, 2, 3]]
c: [1, 2, 3]

删除 a 后的状态:
b id: 2017213039816
b[1] id: 2017213145928
c id: 2017213145928
b: [10, [1, 2, 3]]
c: [1, 2, 3]

通过上述结果可知,使用 del 删除 a 后对 b 和 c 没有造成任何影响。这是因为,在Python中,del语句主要用于删除对象的引用,而不是直接删除数据或释放内存空间。当你使用del删除一个变量引用时,Python的垃圾收集器会在没有其他引用指向同一对象时自动回收其内存。



通过上面分析,我们可以得到以下结论:

  1. 当我们对 a 进行重新赋值时,系统会从内存中调出一个新区域存放我们的数据。而不是在原来的地址处重新复写。
  2. 在Python中,del语句主要用于删除对象的引用,而不是直接删除数据或释放内存空间。当你使用del删除一个变量引用时,Python的垃圾收集器会在没有其他引用指向同一对象时自动回收其内存。
  3. 变量 a 作为变量 b 的一部分被引用,仍然可以互相修改值,这是因为这两部分的地址为同一块内存地址。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值