python中的深拷贝和浅拷贝
python学习 . 2020/04/28发布 . shanyonggang_web . 我要评论 . 82阅读

浅拷贝的深拷贝是面试过程中经常会被问到的基础问题,本文从代码的角度来看看两者的区别

单层拷贝

主要分为两种,针对不可变类型和可变类型,对于不可变类型,如下:

import copy

# 单层拷贝(不可变类型)
a = 'hello'
b = copy.copy(a)
c = copy.deepcopy(a)
print("*"*10)
print(id(a))
print(id(b))
print(id(c))
print("*"*10)

结果如下:

结论:对于不可变类型,深拷贝和浅拷贝内存地址不发生变化,直接引用原有的内存地址。

对于可变类型,如下:

import copy

# 单层拷贝(可变类型)
a1 = ['hello','world','need']
b1 = copy.copy(a1)
c1 = copy.deepcopy(a1)
print("*"*10)
print(id(a1))
print(id(b1))
print(id(c1))
b1.append('hhhh')
print(a1)
print(b1)
print("*"*10)

结果如下:

结论:对于可变类型,深拷贝和浅拷贝内存地址发生变话,为其创建了一个新的内存地址

嵌套拷贝

对于嵌套拷贝,我们主要以四种形式观察其变化,首先外层为不可变类型,内层为可变类型,如下:

# 嵌套拷贝(外不可变、内可变类型)
a2 = (['hello','world','need'],'hello',[1,2,3])
b2 = copy.copy(a2)
c2 = copy.deepcopy(a2)
print("*"*10)
print(id(a2))
print(id(b2))
print(id(c2))
print(id(a2[0]))
print(id(a2[1]))
print(id(b2[0]))
print(id(b2[1]))
print(id(c2[0]))
print(id(c2[1]))
print("*"*10)

结果如下:

结论如下:对于外层不可变、内层可变,深拷贝时内存地址发生变化,内层可变类型的内存地址也发生变化,浅拷贝内外层内存地址均未改变,直接引用原内存

对于外层可变,内层可变类型,如下:

import copy

# 嵌套拷贝(外可变、内可变类型)
a2 = [['hello','world','need'],[1,2,3]]
b2 = copy.copy(a2)
c2 = copy.deepcopy(a2)
print("*"*10)
print(id(a2))
print(id(b2))
print(id(c2))
print(id(a2[0]))
print(id(a2[1]))
print(id(b2[0]))
print(id(b2[1]))
print(id(c2[0]))
print(id(c2[1]))
print("*"*10)

结果如下:

结论:对于外层可变、内层可变,深拷贝时内存地址发生变化,内层可变类型的内存地址也发生变化,浅拷贝外层内存地址改变,内层地址不变,依然引用之前的内存

对于外层不可变,内层不可变类型,如下:

import copy

# 嵌套深拷贝(外不可变、内不可变类型)
a2 = (('hello','world','need'),(1,2,3))
b2 = copy.copy(a2)
c2 = copy.deepcopy(a2)
print("*"*10)
print(id(a2))
print(id(b2))
print(id(c2))
print(id(a2[0]))
print(id(a2[1]))
print(id(b2[0]))
print(id(b2[1]))
print(id(c2[0]))
print(id(c2[1]))
print("*"*10)

结果如下:

结论:对于外层不可变、内层不可变,深拷贝时内存地址未变化,内层可变类型的内存地址也未变化,浅拷贝内外层内存地址不变,依然引用之前的内存

对于外层可变,内层不可变类型,如下:

import copy

# 嵌套深拷贝(外可变、内不可变类型)
a2 = [('hello','world','need'),(1,2,3)]
b2 = copy.copy(a2)
c2 = copy.deepcopy(a2)
print("*"*10)
print(id(a2))
print(id(b2))
print(id(c2))
print(id(a2[0]))
print(id(a2[1]))
print(id(b2[0]))
print(id(b2[1]))
print(id(c2[0]))
print(id(c2[1])) 
print("*"*10)

结果如下:

结论:对于外层可变、内层不可变,深拷贝时内存外层地址发生变化,内层内存不变化,浅拷贝内外层内存地址变化,内层内存地址不变,依然引用之前的内存

总结

  • 对于可变类型的单层拷贝,深拷贝和浅拷贝内存地址均发生变化
  • 对于不可变类型的单层拷贝,深拷贝和浅拷贝内存地址不发生变化,均引用之前的内存地址
  • 嵌套拷贝,对于外层为可变类型,浅拷贝最外层内存地址发生变化,内层内存地址依然与之前相同,不论内层的数据是什么类型
  • 嵌套拷贝,对于外层为不可变类型,浅拷贝最外层内存地址均不发生变化,内层内存地址依然与之前相同,不论内层的数据是什么类型
  • 嵌套拷贝,只要嵌套层中有可变类型,则最外层内存地址发生变化,内部的可变类型内存地址也发生变化,不可变类型不变,依然与之前一样

我写的比较通俗,参考别人最后的总结,如下:

浅拷贝

  • 浅拷贝只做最顶层的数据类型判断
  • 如果顶层是可变类型则创建新的内存空间
  • 如果顶层是不可变数据类型就是引用拷贝

深拷贝

  • 深拷贝做递归拷贝,可以递归拷贝所有的内部嵌套数据(可以理解为循环遍历做浅拷贝判断)
  • 深拷贝递归拷贝遇到可变类型则创建新的内存空间
  • 深拷贝递归拷贝遇到不可变数据类型就是拷贝的引用

  • 有疑问请在下方评论区留言,我会尽快回复。
  • Email私信我: 511248513@qq.com 或添加博主 微信
本文作者:shanyonggang_web
发布时间:2020年4月28日 10:30
许可协议: 署名-非商业性使用 4.0 国际许可协议
知识共享许可协议     转载请保留原文链接及作者
正在加载今日诗词....
您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请狠狠点击下面的


登录 后回复

当前暂无评论,点击登录来做第一个吃螃蟹的人吧!