写在前面

已经见多很多这样的Blog,为什么还想自己写呢?原因很简单,每当学到一个知识时候,尝试着对自己或者别人讲解这个知识点,当别人能听懂的时候,就算是真的理解了。

重要部分

首先,要分清楚id()函数、is和= =运算符 的使用以及区别。id()是返回一个对象的地址;is 比较两个变量的引用是否指向同一个对象;= = 比较两个变量的值是否相等

其次,Python中一切皆对象,所有的对象拥有三个属性:id、type、value,Python对象分两种类型,一是不可变对象,二是可变对象。
不可变对象:该对象所指向的内存中的值不能被改变。一个变量指向的是不可变对象的引用,当对这个变量的值做修改时,由于其所指的值不能被改变,相当于把原来的值复制一份后再改变,这会开辟一个新的地址,这时变量的指向已经发生改变,由原来的指向新开辟的地址。
可变对象:该对象所指向的内存中的值可以被改变。变量改变后,实际上是其所指的值直接发生改变,并没有发生复制行为,也没有开辟新的出地址,变量指向的地址并没有发生改变。

a = 100  #id(a) ->140736904075200
a += 10  #id(a) ->140736904078400
L = ['C#', 'C++', 'Java']   #id(L) ->1627814636224
L.append('Python')            #id(L) ->1627814636224

常见的不可变对象:数字、字符串、元组
常见的可变对象:列表、字典、集合

接下来,看一下这个例子

import copy
is_same_addr = lambda v1,v2:(id(v1)==id(v2))e = 10  #e指向不可变对象
v_1 = e                #直接赋值
v_2 = copy.copy(e) #浅拷贝
print is_same_addr(v_1, e)  #>> True
print is_same_addr(v_2, e)  #>> True

显然,当变量e指向的是不可变对象,采用直接赋值或者拷贝的方式让另一个变量v等于e,实际上两个变量指向的是同一个变量的引用,并没有复制出新的副本

接着,再往下看

e = ['e','jianl', ['Python', 'C++']]
v_1 = e                    #1 赋值
v_2 = e[:]             #2 切片
v_3 = copy.copy(e)     #3 浅拷贝
v_4 = copy.deepcopy(e) #4 深拷贝print is_same_addr(v_1, e)    #>> True
print is_same_addr(v_2, e)  #>> False
print is_same_addr(v_3, e)  #>> False
print is_same_addr(v_4, e)  #>> False

可以看出,除了赋值的方式是复制变量e的引用外, 其余方式都是有开辟新的内存,不算是 ‘假复制’,
因此,我想如果v_2 、v_3、 v_4 不小心发生改变,应该不会影响原变量e的值,依据是他们所指向并不是同一个对象, 真的是这样吗?敲代码看一下

v_2[0] = 'v_2'
v_3[0] = 'v_3'
v_4[0] = 'v_4'
# 输出各个变量的值
>> e  : ['e',   'jianl', ['Python', 'C++']]
>> v_1: ['e',   'jianl', ['Python', 'C++']]
>
>> v_2: ['v_2', 'jianl', ['Python', 'C++']]
>> v_3: ['v_3', 'jianl', ['Python', 'C++']]
>> v_4: ['v_4', 'jianl', ['Python', 'C++']]

似乎是这样,不过到这里还没完,接着试一下对列表里的可变对象修改操作,看下结果又会怎样呢?

v_2[2][0] = 'C#'
v_3[2][0] = 'C#'

分别对v_2[2] 、v_3[2]所指向的列表作同样的修改,两种情况输出的结果一致,而且变量e的值被修改了

e  : ['e', 'jianl', ['C#', 'C++']]
v_1: ['e', 'jianl', ['C#', 'C++']]
v_2: ['e', 'jianl', ['C#', 'C++']]
v_3: ['e', 'jianl', ['C#', 'C++']]
v_4: ['e', 'jianl', ['Python', 'C++']]

同样,再对v_4[2]所指向的列表作同样的修改

v_4[2][0] = 'C#'

结果,只有v_4的值被修改了

e  : ['e', 'jianl', ['Python', 'C++']]
v_1: ['e', 'jianl', ['Python', 'C++']]
v_2: ['e', 'jianl', ['Python', 'C++']]
v_3: ['e', 'jianl', ['Python', 'C++']]
v_4: ['e', 'jianl', ['C#', 'C++']]

为什么会这样呢?来做一个验证, 对比变量指向的对象成员中为可变变量的地址

print is_same_addr(v_1, e),is_same_addr(v_1[2], e[2])    #True   True
print is_same_addr(v_2, e),is_same_addr(v_2[2], e[2])   #False  True
print is_same_addr(v_3, e),is_same_addr(v_3[2], e[2])   #False  True
print is_same_addr(v_3, e),is_same_addr(v_4[2], e[2])   #False  False

水落石出,利用切片[:]属性或者copy()函数实现对一个变量赋值,属于浅拷贝,只是拷贝对象的一部分不可变类型的数据,对于对象里的可变类型对象属性,仅仅是拷贝一个引用;而使用deepcopy()函数实现的是深拷贝,将变量所指向的对象整个复制,开辟新的空间,再由另一个变量指向这块新的空间。

最后

几句话总结:
1 对象有类型,变量无类型,变量是对象的标签;
2 对指向不可变对象变量的值作修改,实际上是改变变量的指向,对象本身是不可能被修改的;指向可变对象变量的值发生改变,实际上是对象本身被修改了;
3 v = e,实际上是将e的引用赋值给v, v e指向同一个变量;
4 v= e[:] 及 v=copy(e),浅拷贝,只复制部分数据,而e所指向的对象中可变类型属性,只是拷贝引用;
5 v = deepcopy(e), 深拷贝,e指向的整个对象被复制,再由v指向;

参考文章:
https://www.jianshu.com/p/9ed9b5ce7bb0

Python 之 = [:] copy deepcopy相关推荐

  1. Python中copy,deepcopy,浅拷贝(“=”)和深拷贝(“copy.deepcopy()”)

    python中对于对象的拷贝分为浅拷贝(copy)和深拷贝(deepcopy)两种方式.其中浅拷贝由"="完成.而深拷贝由copy模块中deepcopy()函数担任. 浅拷贝和深拷 ...

  2. 浅拷贝copy(“=”)和深拷贝(“copy.deepcopy()”)

    python中对于对象的拷贝分为浅拷贝(copy)和深拷贝(deepcopy)两种方式. 其中浅拷贝由"="完成.而深拷贝由copy模块中deepcopy()函数担任. 浅拷贝和深 ...

  3. Python 传值和传址 copy/deepcopy

    传值:被调函数局部变量改变不会影响主调函数局部变量 传址:被调函数局部变量改变会影响主调函数局部变量 Python参数传递方式:传递对象引用(传值和传址的混合方式),如果是数字,字符串,元组则传值:如 ...

  4. [PYTHON] 深度解析copy.copy() 与 copy.deepcopy()

    在列表中,想要复制一个列表,可以使用copy()函数,在列表中,copy()函数与切片 [:] 功能相同 a=[0,1,[0,1]] b=a.copy() c=a[:] -----print b,c- ...

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

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

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

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

  7. Python中copy和deepcopy中的区别

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

  8. python中copy和deepcopy详细区别

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

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

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

最新文章

  1. codeblocks使用指南
  2. 李德毅院士:通用人工智能十问
  3. Java NIO(十五) Path 的用法
  4. C++设计模式实现--策略(Strategy)模式
  5. SqliteHelper整理(转载)
  6. hibernate 表关系映射详解之多对多
  7. 乐鑫esp8266的串口通讯驱动源文件,nonos和rtos版本
  8. 基于JAVA+SpringMVC+MYSQL的ktv预订管理系统
  9. js setInterval() 用法示例
  10. java中的银行界面开发_ATM机银行项目java图形界面
  11. html修改每页显示数量,JS实现动态设置每页显示固定行数
  12. 电子秤查看通道及更改通道方法
  13. 对策《四川省本科毕业论文(设计)抽检实施细则》(二)专业能力
  14. cv个人计算机SCI英文简历模板,个人英文简历模板
  15. 电脑发到,电脑电影怎么传到手机_把电脑上的电影传到手机上的详细教程
  16. 软件测试之测试用例设计(一)
  17. 为什么会出现锟斤拷?
  18. el-table展示枚举值
  19. 如何设计游戏中的道具功能(三)
  20. FPC软排线结构的奥秘

热门文章

  1. 个人计算机cache是什么意思,cache在计算机中的作用是什么?
  2. 深信服上网行为管理设备登录方法、恢复出厂、恢复控制台密码
  3. 无基础的人如何唱好歌、三分钟让你快速学会唱歌技巧
  4. [Qt] TCP客户端与服务器断开连接自动重联机制
  5. The authenticity of host ‘gree129 (192.168.**.129)‘ can‘t be established.
  6. Tita 持续绩效:一对一会议的好处
  7. 吉尔电子烟获1200万天使轮融资
  8. 古董电脑室:2019日记簿(二)
  9. 计算机硬件耗电,耗电大户不一定就“费电”_主板评测-中关村在线
  10. B端和C端产品的理解