参考:Python赋值,copy,deepcopy区别

结论

  • copy()与deepcopy()之间的主要区别是python对数据的存储方式。

  • python2中,需要import copy模块。python3中,直接可以使用copy()方法,但deepcopy()还是需要导入copy模块。

  • 深复制,即将被复制对象完全再复制一遍作为独立的新个体单独存在。所以改变原有被复制对象不会对已经复制出来的新对象产生影响。

  • 等于赋值,并不会产生一个独立的对象单独存在,他只是将原有的数据块打上一个新标签,所以当其中一个标签被改变的时候,数据块就会发生变化,另一个标签也会随之改变。

  • 浅复制要分两种情况进行讨论:

    1)当浅复制的值是不可变对象(数值,字符串,元组)时和“等于赋值”的情况一样。

    2)当浅复制的值是可变对象(列表,字典)时会产生一个“不是那么独立的对象”存在。有两种情况:

    • 第一种情况:复制的对象中无复杂子对象,原来值的改变并不会影响浅复制的值,同时浅复制的值改变也并不会影响原来的值。

    • 第二种情况:复制的对象中有复杂子对象 (例如列表中的一个子元素是一个列表),如果不改变其中复杂子对象,浅复制的值改变并不会影响原来的值。 但是改变原来的值中的复杂子对象的值会影响浅复制的值。

不可变数据类型的copy

import copya='123445'
b=a
c=copy.copy(a)
d=copy.deepcopy(a)print('a===%s'%a)
print('b===%s'%b)
print('c===%s'%c)print('id(a)是:',id(a))
print('id(b)是:',id(b))
print('id(c)是:',id(c))

输出:

a===123445
b===123445
c===123445
id(a)是: 2229108678512
id(b)是: 2229108678512
id(c)是: 2229108678512

分析:不可变的数据类型,等于赋值、浅复制、深复制id都是一样的。

可变数据类型(列表、字典)的copy(元素不包含复杂元素)

import copyl1=[1,2,3,4,5,6]
l2=l1
l3=copy.copy(l1)
l4=copy.deepcopy(l1)l1.append('hello')
l3[3]='world'print('l1====%s'%l1)
print('l2====%s'%l2)
print('l3====%s'%l3)
print('l4====%s'%l4)l4.append('list')
print('l4修改后为====%s'%l4)print('id(l1)是:',id(l1))
print('id(l2)是:',id(l2))
print('id(l3)是:',id(l3))
print('id(l4)是:',id(l4))

输出:

l1====[1, 2, 3, 4, 5, 6, 'hello']
l2====[1, 2, 3, 4, 5, 6, 'hello']
l3====[1, 2, 3, 'world', 5, 6]
l4====[1, 2, 3, 4, 5, 6]
l4修改后为====[1, 2, 3, 4, 5, 6, 'list']id(l1)是: 1510329127816
id(l2)是: 1510329127816
id(l3)是: 1510329128008
id(l4)是: 1510329129288

分析:可变数据类型的浅copy()方法,并不会修改被复制对象。

可变数据类型包含复杂元素的copy

>>> import copy>>> list1=[1,2,3,['hello','hey','hi']]
>>> list2=list1
>>> list3=copy.copy(list1)
>>> list4=copy.deepcopy(list1)>>> id(list1)
2380371448840>>> id(list2)
2380371448840>>> id(list3)
2380371450056>>> id(list4)
2380371450120>>> list1[3].append('list') #改变被复制对象内的列表项,浅复制的也跟着改变了,但是深复制的没有改变>>> id(list1)
2380371448840>>> list2
[1, 2, 3, ['hello', 'hey', 'hi', 'list']]>>> id(list2)
2380371448840>>> list3[1, 2, 3, ['hello', 'hey', 'hi', 'list']]>>> id(list3)
2380371450056>>> list4
[1, 2, 3, ['hello', 'hey', 'hi']]>>> id(list4)
2380371450120>>> list3[3][0]=0 #改变浅复制得到的对象内的列表,被复制对象也改变了,深复制对象没改变>>> list3
[1, 2, 3, [0, 'hey', 'hi', 'list']]>>> list1
[1, 2, 3, [0, 'hey', 'hi', 'list']]>>> id(list1)
2380371448840>>> id(list3)
2380371450056>>> list4
[1, 2, 3, ['hello', 'hey', 'hi']]>>> id(list4)
2380371450120>>> list4.append('hahahha') #改变深复制的来的对象内的一般项,被复制对象没有改变>>> list4
[1, 2, 3, ['hello', 'hey', 'hi'], 'hahahha']>>> list1
[1, 2, 3, [0, 'hey', 'hi', 'list']]>>> list3
[1, 2, 3, [0, 'hey', 'hi', 'list']]>>> id(list1)
2380371448840>>> id(list3)
2380371450056>>> id(list4)
2380371450120>>> list4[3][0]=1 #改变深复制的来的对象内的列表对象,被复制对象没有改变,浅复制对象也没改变>>> list4
[1, 2, 3, [1, 'hey', 'hi'], 'hahahha']>>> list1
[1, 2, 3, [0, 'hey', 'hi', 'list']]>>> list3
[1, 2, 3, [0, 'hey', 'hi', 'list']]>>> id(list4)
2380371450120>>> id(list1)
2380371448840>>> id(list3)
2380371450056>>> list1.append('change')>>> list1
[1, 2, 3, ['list1', 'hey', 'hi', 'list'], 'change']>>> list3
[1, 2, 3, ['list1', 'hey', 'hi', 'list']] #改变被复制对象的一般元素时,浅复制对象没有改变>>> list4
[1, 2, 3, [1, 'hey', 'hi'], 'hahahha']>>> #从始至终,每个对象的id没有改变过

分析:

1.改变被复制对象的一般元素时,浅复制对象没有改变,深复制对象没改变;
2.改变被复制对象的复杂子项中的元素时,浅复制对象跟着改变了,深复制对象没改变;
3.改变浅复制对象的一般项时,被复制对象没有改变,深复制对象没有改变;
4.改变浅复制对象的复杂子项内的元素时,被复制对象改变了,深复制对象没有改变;
5.改变深复制对象的一般项时,被复制对象没有改变,浅复制对象没有改变;
6.改变深复制对象的复杂子项内的元素时,被复制对象没有改变,浅复制对象没有改变。

python的数据存储方式

Python 存储变量的方法跟其他 OOP 语言不同。它与其说是把值赋给变量,不如说是给变量建立了一个到具体值的 reference。

当在 Python 中 a = something 应该理解为给 something 贴上了一个标签 a。当再赋值给 a 的时候,就好象把 a 这个标签从原来的 something 上拿下来,贴到其他对象上,建立新的 reference。 这就解释了一些 Python 中可能遇到的诡异情况:

>> a = [1, 2, 3]
>>> b = a
>>> a = [4, 5, 6] //赋新的值给 a>>> a
[4, 5, 6]>>> b
[1, 2, 3]# a 的值改变后,b 并没有随着 a 变>>> a = [1, 2, 3]
>>> b = a
>>> a[0], a[1], a[2] = 4, 5, 6 //改变原来 list 中的元素>>> a
[4, 5, 6]>>> b
[4, 5, 6]# a 的值改变后,b 随着 a 变了

上面两段代码中,a 的值都发生了变化。区别在于,第一段代码中是直接赋给了 a 新的值(从 [1, 2, 3] 变为 [4, 5, 6]);而第二段则是把 list 中每个元素分别改变。而对 b 的影响则是不同的,一个没有让 b 的值发生改变,另一个变了。怎么用上边的道理来解释这个诡异的不同呢?首先把 [1, 2, 3] 看成一个物品。a = [1, 2, 3] 就相当于给这个物品上贴上 a 这个标签。而 b = a 就是给这个物品又贴上了一个 b 的标签。

  • 第一种情况:a = [4, 5, 6] 就相当于把 a 标签从 [1 ,2, 3] 上撕下来,贴到了 [4, 5, 6] 上。在这个过程中,[1, 2, 3] 这个物品并没有消失。 b 自始至终都好好的贴在 [1, 2, 3] 上,既然这个 reference 也没有改变过。 b 的值自然不变。
  • 第二种情况:a[0], a[1], a[2] = 4, 5, 6 则是直接改变了 [1, 2, 3] 这个物品本身。把它内部的每一部分都重新改装了一下。内部改装完毕后,[1, 2, 3] 本身变成了 [4, 5, 6]。而在此过程当中,a 和 b 都没有动,他们还贴在那个物品上。因此自然 a b 的值都变成了 [4, 5, 6]。

搞明白这个之后就要问了,对于一个复杂对象的浅copy,在copy的时候到底发生了什么?
再看一段代码:

>>> import copy>>> origin = [1, 2, [3, 4]]
#origin 里边有三个元素:1, 2,[3, 4]>>> cop1 = copy.copy(origin)
>>> cop2 = copy.deepcopy(origin)>>> cop1 == cop2
True>>> cop1 is cop2
False
#cop1 和 cop2 看上去相同,但已不再是同一个object>>> origin[2][0] = "hey!">>> origin[1, 2, ['hey!', 4]]>>> cop1
[1, 2, ['hey!', 4]]>>> cop2
[1, 2, [3, 4]]
#把origin内的子list [3, 4] 改掉了一个元素,观察 cop1 和 cop2

copy概念图如下:

copy(浅复制)对于一个复杂对象的子对象并不会完全复制,什么是复杂对象的子对象呢?就比如序列里的嵌套序列,字典里的嵌套序列等都是复杂对象的子对象。对于子对象,python会把它当作一个公共镜像存储起来,所有对他的复制都被当成一个引用,所以说当其中一个引用将镜像改变了之后另一个引用使用镜像的时候镜像已经被改变了。

所以说看这里的origin[2],也就是 [3, 4] 这个 list。根据 shallow copy 的定义,在 cop1[2] 指向的是同一个 list [3, 4]。那么,如果这里我们改变了这个 list,就会导致 origin 和 cop1 同时改变。这就是为什么上边 origin[2][0] = “hey!” 之后,cop1 也随之变成了 [1, 2, [‘hey!’, 4]]。

deepcopy概念图如下:

deepcopy的时候会将复杂对象的每一层复制一个单独的个体出来。
这时候的 origin[2] 和 cop2[2] 虽然值都等于 [3, 4],但已经不是同一个 list了。即我们寻常意义上的复制。

Python:赋值,copy和deepcopy区别相关推荐

  1. python中copy和deepcopy详细区别

    python中copy和deepcopy 在 python 中,标识一个对象唯一身份的是:对象的id(内存地址),对象类型,对象值. deepcopy是真正意义上的复制,深拷贝,被复制对象完全复制一遍 ...

  2. copy与deepcopy区别

    copy与deepcopy区别 1.deepcopy: 将复制对象完全复制一边,并作为一个独立的新个体单元存在.即使改变被复制对象,deepcopy新个体也不会发生变化 2.copy: 不产生一个独立 ...

  3. python中copy和deepcopy的区别_python里shadowcopy和deepcopy的区别

    python中,经常会需要拷贝特定对象,在此可能就会遇到各种bug,原因就是明白这三种操作的区别,赋值,浅拷贝,深拷贝. 赋值(=),浅拷贝(copy)和深拷贝(deepcopy)比较容易区别开的是赋 ...

  4. Python中copy()和deepcopy()的区别

    同样是copy,二者有什么不同呢今天我们就一探究竟!!! 关于copy()和deepcopy()的第一篇博客 初学编程的小伙伴都会对于深浅拷贝的用法有些疑问,今天我们就结合python变量存储的特性从 ...

  5. Python中copy和deepcopy中的区别

    最近在学习 Python编程,遇到copy和deepcopy感到很困惑,现在针对这两个方法进行区分,一种是浅复制(copy),一种是深度复制(deepcopy). 首先说一下deepcopy,所谓的深 ...

  6. python:copy()和deepcopy()区别

    1.对象的赋值 都是进行对象引用(内存地址)传递,即'' b is a'' ,a 变 b 也变 2.copy.copy(x):浅拷贝 会创建一个新的对象,即 "b is not a" ...

  7. python deepcopy_【Python】copy和deepcopy的区别

    [人生苦短,我用Python] 直入主题,在Python中,我们常常用到copy这个关键字,对于之前做iOS开发的我来说Python中的深拷贝和浅拷贝和iOS中的深浅拷贝还是有一些区别的. 浅拷贝是对 ...

  8. 2020-09-18 python中copy()和deepcopy()详解

    首先直接上结论: -–我们寻常意义的复制就是深复制,即将被复制对象完全再复制一遍作为独立的新个体单独存在.所以改变原有被复制对象不会对已经复制出来的新对象产生影响. -–而浅复制并不会产生一个独立的对 ...

  9. python中copy()和deepcopy()详解

    参考文章 http://iaman.actor/blog/2016/04/17/copy-in-python **首先直接上结论: -–我们寻常意义的复制就是深复制,即将被复制对象完全再复制一遍作为独 ...

最新文章

  1. NO.7 今天我们是实用派,看看业务选择和部署以及常用故障解决方案是怎么做的...
  2. leetcode算法题--全排列
  3. C 语言的实际运用 ---150809124
  4. java query api_ElasticSearch(十二) Bool Query JAVA API
  5. hadoop深入研究:(五)——Archives
  6. 【OS学习笔记】二十七 保护模式八:任务切换的方法之----jmp与call的区别以及任务的中断嵌套
  7. FPGA复位激励编写(方法三)
  8. 荣耀Magic4性能体验超苹果再次实锤!非官方游戏性能对比出炉
  9. 【IBM Tivoli Identity Manager 学习文档】2 部署准备知识
  10. Golang最佳Web框架对比
  11. Agisoft Metashape Professional for Mac(三维建模软件)
  12. 第一周golang学习:--基本数据类型与string字符串类型之间的转换
  13. 震旦adc225打印机连接计算机,震旦ADC225打印机驱动
  14. 计算机一些常用快捷指令
  15. polyval polyvalm
  16. UVALive(LA) 4487 Exclusive-OR(带权并查集)
  17. Error converting data type...
  18. 麒麟服务器系统搭建nfs共享
  19. SSM框架解决QQ邮箱激活535 Error: ÇëʹÓÃÊÚȨÂëµÇ¼¡£ÏêÇéÇë¿´及端口25被占用问题
  20. 猎豹掌门人出走,傅盛的“梦游”该醒醒了

热门文章

  1. Qt中取消信号槽的绑定关系
  2. 普通护照出国免签及落地签国家和地区
  3. smartsvn 忽略文件夹_SVN、Git设置提交时忽略的文件
  4. mstar(mark)
  5. gz是什么意思饭圈_光遇:玩家和朋友的日常对话,饭圈女孩太真实了,你有同感吗?...
  6. 修行漫谈——何为放下
  7. MYSQL 显示表结构
  8. php中stmt是什么意思,PHP的mysqli_stmt_init()函数讲解
  9. 计算机作文 六年级,我和电脑作文(2篇)
  10. 把 Python 打包exe如何让文件更小