直接赋值,深拷贝与浅拷贝


首先,简单理解一下概念:(注意:以下概念都是建立在可变数据类型上,包括列表list和字典dict)

1、直接赋值:当创建一个对象a,然后把它赋给另一个变量b的时候,python并没有拷贝这个对象,而只是拷贝了这个对象的引用;原始列表改变,被赋值的b也会做相同的改变;

 

 

 

2、copy浅拷贝,只拷贝了父对象,没有拷贝子对象,所以原始数据的子对象的改变,浅拷贝的子对象也会改变;但是父对象的改变,浅拷贝的父对象不会改变;

 

 

 

3、深拷贝,包含父对象里面的子对象的拷贝,所以原始对象的改变不会造成深拷贝里任何子元素的改变;

 

 

 接下来我们来跑一个代码例子,原始对象包含子对象的例子

import copy# 列表型,即可变数据类型,但不包含子对象
a=[1,2] b=copy.deepcopy(a) c=a d=copy.copy(a) e=[1,2] print(b is a) print(c is a) print(d is a) print(e is a) print("变化前:",a,b,c,d,e,"\n") a.append(5) print("变化后:",a,b,c,d,e,"\n")

输出结果:

False True False False 变化前: [1, 2] [1, 2] [1, 2] [1, 2] [1, 2]
变化后: [1, 2, 5] [1, 2] [1, 2, 5] [1, 2] [1, 2]

分析:

1、我们创建一个列表型数据a,即可变数据类型,但不包含子对象;

PS:我们使用身份运算符is,判断两个标识符是不是引用自一个对象

x is y, 类似 id(x) == id(y) , 如果引用的是同一个对象则返回 True,否则返回 False

2、b深拷贝a,与a不是引用自一个对象,所以输出false

3、c是a直接赋值的,拷贝了a的引用,即与a引用自同一个对象,所以输出true

4、d浅拷贝a,与a也不是引用自同一个对象,所以输出false

5、e虽然和a值一样,但属于不同的对象,在内存中有不一样的地址,所以输出false

6、a对象增加值5,只有直接赋值的c的值同步发生了改变,因为深拷贝和浅拷贝的父对象和原始对象都是不一样的了(可以回头看看概念和图例),而e对象本来就是与a无关的,所以更加不会发生变化。

我们再跑一个代码例子,原始对象包含子对象的例子

import copy
#
列表型,即不可变数据类型,但包含子对象 a=[1,2,[11,22]] b=copy.deepcopy(a) c=a d=copy.copy(a) e=[1,2,[11,22]] print(b is a) print(c is a) print(d is a) print(e is a) print("变化前:",a,b,c,d,e,"\n") a[2].append(33) print("变化后:",a,b,c,d,e,"\n")

输出结果:

False True False False 变化前: [1, 2, [11, 22]] [1, 2, [11, 22]] [1, 2, [11, 22]] [1, 2, [11, 22]] [1, 2, [11, 22]] 变化后: [1, 2, [11, 22, 33]] [1, 2, [11, 22]] [1, 2, [11, 22, 33]] [1, 2, [11, 22, 33]] [1, 2, [11, 22]]

分析:

1、我们创建一个列表型数据a,即可变数据类型,且包含子对象,子对象也是个列表;

PS:我们使用身份运算符is,判断两个标识符是不是引用自一个对象

x is y, 类似 id(x) == id(y) , 如果引用的是同一个对象则返回 True,否则返回 False

2、b深拷贝a,与a不是引用自一个对象,所以输出false

3、c是a直接赋值的,拷贝了a的引用,即与a引用自同一个对象,所以输出true

4、d浅拷贝a,与a也不是引用自同一个对象,所以输出false

5、e虽然和a值一样,但属于不同的对象,在内存中有不一样的地址,所以输出false

6、a对象的子对象列表增加值33,除了直接赋值的c的值同步发生了改变,浅拷贝的子对象也发生了改变,因为浅拷贝的子对象和原始对象中的子对象引用的是同一个对象!(可以回头看看概念和图例),而e对象本来就是与a无关的,所以依然不会发生变化。

 

最后,我们来思考一个问题,如果是不可变数据类型,结果是什么?

import copy # 数值型,即不可变数据类型
a=1 b=copy.deepcopy(a) c=a d=copy.copy(a) e=1
print(b is a) print(c is a) print(d is a) print(e is a) print("变化前:",a,b,c,d,e,"\n") a=2
print("变化后:",a,b,c,d,e,"\n")

输出结果:

True True True True 变化前: 1 1 1 1 1 变化后: 2 1 1 1 1

分析:

1、我们创建一个数值型数据a,即不可变数据类型;

PS:我们使用身份运算符is,判断两个标识符是不是引用自一个对象

x is y, 类似 id(x) == id(y) , 如果引用的是同一个对象则返回 True,否则返回 False

2、结果发现无论是深拷贝、浅拷贝、直接赋值还是新建一个数值一样的变量,在内存中的地址都是一样的,身份运算输出都是true。这是因为:不可变数据类型,不允许变量的值发生变化,如果改变了变量的值,相当于是新建了一个对象,而对于相同的值的对象,在内存中则只有一个对象(一个地址)!

6、所以当a变量的值改变之后,其他的变量都不会改变,因为是a引用的对象变了,而其他变量的引用并没有发生改变,依然引用“数值1”这个对象。

由此可见,对于不可变数据类型(数值型、字符串型和元组),拷贝都是无差别的。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM