python学习笔记:引用、浅拷贝和深拷贝(底层原理)

前言

在python中“一切皆对象”,包括整数(int),小数(float)等

引用

Python解释器维护了一个内部的数据结构,称为命名空间或符号表,它将变量名与对象的内存地址关联起来。当您创建一个变量并将其赋值为某个对象时,实际上是将变量名与对象的内存地址关联起来,从而使变量可以引用该对象。

在python中,变量是一个标识符,解释器遇到这个标识符的时候,会在python的“符号表”里面对应它的位置,并返回它对应的对象的地址。在赋值操作时,符号表将会被编辑,标识符对应的对象地址被改变,使得变量可以引用新的对象。

比如:当我执行:

a = ‘hello’

b = 'world'

拓展:

python的不可变对象用的是引用计数机制。为了节省内存和提高效率,如果创建多个值相同的变量,他们指向的对象一般是相同的。比如

a = 1
b = a
c = b

执行完这段代码之后,a,b,c都指向同一个地址(同个对象),这个地址的引用次数为3。但是当我们改变其中一个变量的值(实际上是想要改变变量引用的对象的值)得时候,其他两个变量的值不会改变。这是为什么?这是因为int是不可变类型,所以实际上当你想要改变变量引用的对象的值的时候,不会真的改变这个对象的值,而是新建了一个对象,然后让变量引用这一个新的对象,相应地“1”的引用次数减少为2。

若执行:b = 2,不会改变0x11的值,而是在内存里新建一个值为2的对象:

(当地址的引用次数变为0,python会回收这块内存。)

浅拷贝

哪些操作属于:除了copy 模块中的 deepcopy 函数,其他均为浅拷贝

就是只拷贝一层的信息,不管是拷贝最外层的引用(直接赋值),还是次外层的引用(切片),只一层。

深拷贝

只有 copy 模块中的 deepcopy 函数能够实现

新建新的对象,递归重建完全一样的引用结构。

浅拷贝和深拷贝的区别

浅拷贝和深拷贝的区别不在深浅,而在对引用结构的拷贝是全面的还是部分的。

有时候浅拷贝操作的效果和深拷贝完全相同,比如

a = [1, 2, 3]
b = a[:]
a[0] = 4

print(b[0])

这时b[0]的值没有改变还是1,也就是b = a[:]等价于 b = copy.deepcopy(a)

这是因为切片虽然是浅拷贝,但是不是拷贝a数组这个对象的引用,而是a数组内容里面每个对象的引用,由于前文提到的int类型对象的不可变性,当我们尝试改变a[0]引用的整型对象的值得时候,会新建一个新对象,这个对象的值被改成4,这就和b没什么关系了。

所以我把切片赋值这样的浅拷贝称为“拷贝次外层”的浅拷贝。和我用循环通过下标赋值类似。

但当浅拷贝对象是可变对象时,浅拷贝和深拷贝的区别就显现出来了:

示例:

a = [1, 2, [3, 4]]
b = a[:]  # 切片操作
b[0] = 100  # 修改 b 的第一个元素
b[2][0] = 300  # 修改 b 的嵌套列表中的元素

print(a)  # 输出:[1, 2, [300, 4]]

在上述示例中,切片复制了包含整数的部分,因此修改 b[0] 不会影响 a,但它仍然共享嵌套列表中的引用,因此修改 b[2][0] 也会影响 a。这说明切片是浅拷贝的行为,只适用于最外层的元素。

总结一下,就是如果改变一个变量,另一个也跟着改变了,就是因为两个引用了相同的可变对象。

有什么问题,欢迎评论提出。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值