参考链接:

1. 介绍python中的可变类型与不可变类型:https://blog.csdn.net/answer3lin/article/details/86430074

(也可以参考转载博客 Python中的不可变对象类型与可变对象类型)

2. 介绍等号赋值、copy、deepcopy的区别:https://blog.csdn.net/qq_26442553/article/details/82218403

建议读者首先明白python中变量的本质、可变对象类型与不可变对象类型的区别,之后对于深浅拷贝会容易理解。


1. 等号"="

“=”的作用是引用原对象的在内存中的地址,让新对象指向这个地址。

1.1 不可变对象

对于不可变对象,其值本身不允许被修改数值的修改实际上是让变量指向了一个新的对象(新创建的对象)。

图1. 不可变对象类型"="拷贝

 # 1.使用=复制不可变对象的值,以及复制以后修改其值后的变化。
val1 = 1000
val2 = val1
print("val1 is :{0},val2 is :{1}".format(val1,val2))
# val1 is :1000,val2 is :1000
print(id(val1),id(val2))
# 139692380387760 139692380387760 # 修改val1的值,因为val1是不可变类型,修改其值,会重新给新值分配内存,然后指向他。
val1 += 1
print(val1,id(val1),val2,id(val2))
# 1001 139692380387216 1000 139692380387760

1.2 可变对象类型

对于可变对象类型,"="会引用对象地址,对其进行修改,只会改变对象值的内容,并不修改该对象(不创建新对象,不更改指针指向的地址)。

Tips:

list对象的地址和list[0]对象的地址是不同的。可以理解为list这个组合对象中插入的是其中各个对象的地址的引用。

图2. list对象

 #1.使用=复制可变对象的值,以及复制以后修改其值后的变化。
ls1 =[1,2,3,4]
ls2 = ls1
print(id(ls1),id(ls2))
# 140520429283400 140520429283400
# 直接使用=复制变量,内存地址一样,值也一样。
print(ls1,ls2)
#[1, 2, 3, 4] [1, 2, 3, 4]
#直接使用=复制变量,内存地址一样,值也一样。
#这时候修改可变对的值,因为其值可变,所以只需要在原内存地址上修改即可。
ls1.append(5)
print(id(ls1),id(ls2))
# 140520429283400 140520429283400
#可变对象修改其值,内存引用不变
print(ls1,ls2)
#[1, 2, 3, 4, 5] [1, 2, 3, 4, 5] 因为两个变量的内存指向一样,所以值也一样。 print(id(ls1), id(ls2))
print(id(ls1[0]), id(ls2[0]))
print(id(ls1[1]), id(ls2[1]))
print(id(ls1[2]), id(ls2[2]))
# 140520429283400 140520429283400
# 94472536902176 94472536902176
# 94472536902208 94472536902208
# 94472536902240 94472536902240

2. copy

2.1 不可变对象类型

效果同"="中的不可变对象

2.2 可变对象类型

对于copy一个可变对象类型的对象,会重新创建一个新的对象,如果原对象是一个组合对象(比如list, 类实例等),会将原组合对象中的各个对象的引用插入到新创建的对象中

注意,copy只是将其第一层组成对象的内存地址引用过来,并不迭代的引用组成对象的组成对象的地址!所以,如果其组成对象是可变类型,虽然引用地址不变,但其内容可能会变化。详见下面两个例子:

例1.

 import copy
ls1 =[1,2,3,4]
ls2 = copy.copy(ls1)
print(id(ls1), id(ls2))
# 140616587448072 140616587497224 ls1.append(5)
print(ls1,ls2)
#[1, 2, 3, 4, 5] [1, 2, 3, 4] print(id(ls1), id(ls2))
print(id(ls1[0]), id(ls2[0]))
# 140616587448072 140616587497224
# 94889387870752 94889387870752

例2.

 origin = [1, 2, [3, 4]]
cop1 = copy.copy(origin)
origin[2][0] = "hey!" #修改数据源的值
print(cop1)
#[1, 2, ['hey!', 4]]

对于例2的解释

  

图3. origin = [1, 2, [3, 4]]的内部结构                                               图4. copy的实现

可以看出copy只在新对象中插入了第一层的地址引用. 其中只有有橘色框的对象是新建的对象。

那么如果想要拷贝前后两个对象完全互相独立,互不影响要怎样做呢?用deepcopy,递归地将组合对象内部的对象进行深层引用。

3. deepcopy

copy与deepcopy的区别:

The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or class instances):

  • shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.

  • deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.

 origin = [1, 2, [3, 4]]
cop2 = copy.deepcopy(origin)
origin[2][0] = "hey!" #修改数据源的值
print(cop2) # [1, 2, [3, 4]]

对比2.2的例2会发现deepcopy递归的将组合对象的每一层的对象都进行了复制。因此,original的对象与deep copy之后的对象是内存地址完全不同的,完全独立的。

         

图3. origin = [1, 2, [3, 4]]的内部结构                             图4. copy的实现                                                                              图5. deepcopy与copy实现的对比

其中橘色是deepcopy实现,不仅新建了第一层addr9处的对象,也递归地新建了addr10处的对象,并将addr10引用插入到addr9处的对象中;递归到指向不可变类型的对象为止;因而原对象与新对象是完全独立,互不影响的。

其中绿色是copy实现,仅新建了第一层addr8处的对象,直接将addr5处对象的引用插入到addr8中,并没有为其重新开辟空间,新建对象,因而,原对象中更深层次中内容的变换,会直接影响新对象内容,二者并非完全独立。

所以,慎用copy~

[Python] 等号赋值, copy, deepcopy的区别的更多相关文章

  1. Python 的直接赋值、Deepcopy、Copy的区别

    直接赋值: 其实就是对象的引用 浅拷贝(copy): 只拷贝符对象,不会拷贝对象内部的子对象 深拷贝(deepcopy): copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象 有图有 ...

  2. 从python中copy与deepcopy的区别看python引用

    讨论copy与deepcopy的区别这个问题要先搞清楚python中的引用.python的内存管理. python中的一切事物皆为对象,并且规定参数的传递都是对象的引用.可能这样说听起来比较难懂,对比 ...

  3. 深入理解Python中赋值、深拷贝(deepcopy)、浅拷贝(copy)

    赋值 python跟java中的变量本质是不一样的,Python的变量实质上是一个指针(int型或str型),而java的变量是一个可操作的存储空间. a = 123b = a print(id(a) ...

  4. python中copy与deepcopy的区别

    目录 区别 python代码举例 区别 高级语言中变量是对内存及其地址的抽象 copy.copy(object), 拷贝的是内嵌套结构的地址引用,当前到结构发生变化的时候,浅拷贝也相应的改变. cop ...

  5. 关于python中赋值、浅拷贝、深拷贝之间区别的深入分析

    当重新学习了计算机基础课程<数据结构和算法分析>后再来看这篇自己以前写的博文,发现错误百出.python内置数据类型之所以会有这些特性,归根结底是它采用的是传递内存地址的方式,而不是传递真 ...

  6. Python中的Copy和Deepcopy

    一,Python的对象: Python存在大量的对象,我们一般提到的对象都是C中的结构体在堆中申请的一块内存(以CPython为例),每一个对象都有ID,可以通过ID(Object)获得.对象的范围包 ...

  7. Python 函数参数引用(传值/传址)/copy/deepcopy

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

  8. Python学习-赋值、浅copy和深copy

    Python Copy: 在Python语言中,分为浅拷贝和深拷贝两种形式,也就是官方文档中的Shadow copy和Deep copy.在对简单的对象(object)进行复制时,两者没有区别,如下面 ...

  9. python中深copy,浅copy与赋值语句的区别

    以下详细讲解:python深复制,浅复制与赋值语句的区别 1. '='赋值语句,常规复制只是将另一个变量名关联到了列表,并不进行副本复制,实例如下: var1=[12,35,67,91,101]var ...

随机推荐

  1. mysql 8.x 集群出现:Last_IO_Error: error connecting to master 'repl@xxx:3306' - retry-time: 60 retries: 1

    网上的经验:网络不同,账号密码不对,密码太长,密码由 # 字符:检查MASTER_HOST,MASTER_USER,MASTER_PASSWORD(不知道 MASTER_LOG_FILE 有没有影响) ...

  2. Struts框架的使用初步

    Struts框架的使用初步: A:Apache下载struts.2.1.8.rar包. B:解压空工程,进入apps目录. C:将struts2的基本jar包拷到工程的lib目录中. D:配置web. ...

  3. ptf转图片

    1.spire 官方的有水印,通过引用 //private readonly static PdfDocument doc = new PdfDocument(); //public static S ...

  4. 佳能单反SDK 步骤

    EdsInitializeSDK(); EdsGetCameraList(&eclr);//获取相机列表 EdsGetChildCount(eclr, &camCount);  //获 ...

  5. luogu P5471 [NOI2019]弹跳

    luogu 因为是一个点向矩形区域连边,所以可以二维数据结构优化连边,但是会MLE.关于维护矩形的数据结构还有\(KD-Tree\),所以考虑\(KDT\)优化连边,空间复杂度\(m\sqrt n\) ...

  6. Winfrom 简单的进度条小程序

    使用Winform空间编写简单的进度条小程序: 所需控件:Lable 标签  TextBox  文本框  progressBar  进度条控件  timer 定时器 下面是源码及效果图: /// &l ...

  7. 通过sql判断时间区间是否存在数据

    在做项目的时候遇到过一个问题,用户需要获取当前月或者几个月的数据,但是有一个要求,如果已经存在一张单已经包含了这几个月的数据,那么就不能再提取到重复的数据. 其实这个问题,我做完了我的方式之后才发现, ...

  8. dart 函数练习

    import 'dart:convert'; import 'dart:html'; void main() { _getIPAddress() { final url = 'https://http ...

  9. Phoenix中的timestamp字段查询以及timestamp的比较查询

    1 查询语法 SELECT TO_CHAR(createtime, 'yyyy-MM-dd HH:mm:ss') FROM USER 2 需要比较timestamp的语法查询 select * fro ...

  10. Oracle笔记(九) 表的创建及管理

    对于数据库而言实际上每一张表都表示的是一个数据库的对象,而数据库对象指的就是DDL定义的所有操作,例如:表.视图.索引.序列.约束等等,都属于对象的操作,所以表的建立就是对象的建立,而对象的操作主要分 ...