注册

Python对象的浅拷贝与深拷贝

在讲我们深浅拷贝之前,我们需要先区分一下拷贝和赋值的概念。看下面的例子

a = [1,2,3]

赋值:

b = a

拷贝:

b = a.copy()

上面的两行代码究竟有什么不同呢?带着这个问题,继续

Python对象的浅拷贝与深拷贝_递归



看了上面这张图,相信大家已经对直接赋值和拷贝有了一个比较清楚的认识。

直接赋值:复制一个对象的引用给新变量
拷贝:复制一个对象到新的内存地址空间,并且将新变量引用到复制后的对象

我们的深浅拷贝只是对于可变对象来讨论的。 不熟悉的朋友需要自己去了解可变对象与不可变对象哦。

1 对象的嵌套引用

a = { "list": [1,2,3] }

上面的代码,在内存中是什么样子的呢?请看下图:

Python对象的浅拷贝与深拷贝_递归_02



原来,在我们的嵌套对象中,子对象也是一个引用。

2 浅拷贝

Python对象的浅拷贝与深拷贝_python_03



如上图所示,我们就可以很好的理解什么叫做浅拷贝了。

浅拷贝:只拷贝父对象,不会拷贝对象的内部的子对象。内部的子对象指向的还是同一个引用

上面 的 a 和 c 是一个独立的对象,但他们的子对象还是指向统一对象

2.1 浅拷贝的方法

  • .copy()

a = {"list": [1,2,3] }
b = a.copy()
  • copy模块

import copy
a = {"list": [1,2,3] }
b = copy.copy(a)
  • 列表切片[:]

a = [1,2,3,[1,2,3]]
b = a[1:]
  • for循环

a = [1,2,3,[1,2,3]]
b = []
for i in a:
  b.append(i)

2.2 浅拷贝的影响

a = {"list":[1,2,3]}
b = a.copy()
a["list"].append(4)

print(a)
# {'list': [1, 2, 3, 4]}

print(b)
# {'list': [1, 2, 3, 4]}

在上面的例子中,我们明明只改变 a 的子对象,却发现 b 的子对象也跟着改变了。这样在我们的程序中也许会引发很多的BUG。

3 深拷贝

上面我们知道了什么是浅拷贝,那我们的深拷贝就更好理解了。

Python对象的浅拷贝与深拷贝_python_04



深拷贝:完全拷贝了父对象及其子对象,两者已经完成没有任何关联,是完全独立的。

import copy
a = {"list":[1,2,3]}
b = copy.deepcopy(a)
a["list"].append(4)

print(a)
# {'list': [1, 2, 3, 4]}

print(b)
# {'list': [1, 2, 3,]}

上面的例子中,我们再次修改 a 的子对象对 b 已经没有任何影响

4 手动实现一个深拷贝

主要采用递归的方法解决问题。判断拷贝的每一项子对象是否为引用对象。如果是就采用递归的方式将子对象进行复制。

def deepcopy(instance):
  if isinstance(instance, dict):
      return {k:deepcopy(v) for k,v in instance.items() }
   
  elif isinstance(instance, list):
      return [deepcopy(x) for x in instance]
   
  else:
      return instance

a = {"list": [1,2,3]}
b = deepcopy(a)

print(a)
# {'list': [1, 2, 3]}

print(b)
# {'list': [1, 2, 3]}

a["list"].append(4)
print(a)
# {'list': [1, 2, 3, 4]}

print(b)
# {'list': [1, 2, 3]}

创作不易,且读且珍惜。如有错漏还请海涵并联系作者修改,内容有参考,如有侵权,请联系作者删除。如果文章对您有帮助,还请动动小手,您的支持是我最大的动力。

作者:趣玩Python
来源:https://blog.51cto.com/u_14666251/4716452

0 个评论

要回复文章请先登录注册