码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2020-02-11 19:19:19      阅读:73      评论:0      收藏:0      [点我收藏+]

标签:列表   包括   运算   src   size   als   对象引用   元组   idt   

首先,简单理解一下概念:(注意:以下概念都是建立在可变数据类型上,包括列表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”这个对象。

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

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

标签:列表   包括   运算   src   size   als   对象引用   元组   idt   

原文地址:https://www.cnblogs.com/cyanlee/p/12296044.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!