Python —— 深拷贝 VS 浅拷贝
来源:互联网 发布:单片机时序图 编辑:程序博客网 时间:2024/06/06 00:39
1. 对象的赋值:
(1)代码:
A = ['nupt',56,['I','you','he']]B = A # 把A赋值给B# 比较A和B的值print A>>>['nupt',56,['I','you','he']]print B >>>['nupt',56,['I','you','he']] # B的值与A相同# 比较A和B所在的地址print id(A) >>>58890248print id(B) >>>58890248 # B的地址与A相同# 比较A中的每个元素与B中每个元素的地址print [id(ele) for ele in A]>>>[59288352L,57107912L,58888776L]print [id(ele) for ele in B]>>>[59288352L,57107912L,58888776L] # B中每个元素所在地址与A相同# 更改A的值,看B的各项变化A[0] = 'NanJing'A[2].append('she')# 比较A和B的值print A>>>['NanJing',56,['I','you','he','she']]print B >>>['NanJing',56,['I','you','he','she']] # B的值仍与A相同# 比较A和B所在的地址print id(A) >>>58890248 # A的地址不变print id(B) >>>58890248 # B的地址仍与A相同# 比较A中的每个元素与B中每个元素的地址print [id(ele) for ele in A]>>>[59285712L,57107912L,58888776L] # A[0]地址变了,A[2]没变print [id(ele) for ele in B]>>>[59285712L,57107912L,58888776L] # B中每个元素所在地址与A相同
(2)代码分析:
- 首先,创建了一个名为A的变量,这个变量指向一个list对象,变量A及其列表元素所存储的地址如下图:
- 然后,通过A向B赋值,那么B将指向A的对象(内存地址),即:B is A, B[ele] is A[ele],变量B及其列表元素的地址如下图:
- 接着,变量A的元素发生改变。
A[0]=’NanJing’,A[0]是str类型变量,str是不可变类型,所以修改时会产生一个新对象替换旧对象,也就相应产生一个新地址;
A[2].append(‘she’),A[2]是list类型变量,list是可变类型,修改时不会产生新对象,故list本身内存地址不变: - 由于A和B指向同一个对象,所以对A的任何修改都会体现在B上:
下面来看看
2. 浅拷贝:copy.copy( )
(1)代码:
import copy # 导入copy模块A = ['njupt',56,['I','you','he']]B = copy.copy(A) # 把A浅拷贝给B# 比较A和B的值print A>>>['njupt',56,['I','you','he']]print B >>>['njupt',56,['I','you','he']] # 浅拷贝的B,值与A相同# 比较A和B所在的地址print id(A) >>>58890824print id(B) >>>59328584 # 浅拷贝的B,地址与A不同# 比较A中的每个元素与B中每个元素的地址print [id(ele) for ele in A]>>>[59288312L,57107912L,58219080L]print [id(ele) for ele in B]>>>[59288312L,57107912L,58219080L] # 浅拷贝的B,元素所在地址与A相同# 更改A的值,看B的各项变化A[0] = 'NanJing'A[2].append('she')# 比较A和B的值print A>>>['NanJing',56,['I','you','he','she']]print B >>>['njupt',56,['I','you','he','she']] # 注意:浅拷贝的B,值与A不同# 比较A和B所在的地址print id(A) >>>58890824 # A的地址不变print id(B) >>>59328584 # 浅拷贝的B,地址不变,仍与A不同# 比较A中的每个元素与B中每个元素的地址print [id(ele) for ele in A]>>>[59286912L,57107912L,58219080L] # A[0]地址变了,A[2]没变print [id(ele) for ele in B]>>>[59288312L,57107912L,58219080L] # B中每个元素所在地址与A相同
(2)代码分析:
- 首先,创建了一个名为A的变量,这个变量指向一个list对象,变量A及其列表元素所存储的地址如下图:
- 然后,对A指向的对象进行浅拷贝,浅拷贝会创建一个新对象赋值给B,那么B指向的对象则不是A所指的对象,即:B is not A;但对于对象内部的元素,浅拷贝会使用原始元素的引用(内存地址),即:B[ele] is A[ele]
- 接着,变量A的元素发生改变。
A[0]=’NanJing’,A[0]是str类型变量,str是不可变类型,所以修改时会产生一个新对象替换旧对象,也就相应产生一个新地址;
A[2].append(‘she’),A[2]是list类型变量,list是可变类型,修改时不会产生新对象,故list本身内存地址不变: - 由于B[2]和A[2]指向的同一地址,若存储在此地址的内容有变化,则A[2]和B[2]的内容皆会改变。因此当A[2]更新后(地址不变),B[2]的内容也随之改变;
而A[0]更新后,其旧对象被新对象替代,即新地址替代了旧地址,而B[0]指向的旧地址,其存储的内容并未改变,因此B[0]不变:
再来看看
3. 深拷贝copy.deepcopy( ):
(1)代码
import copy # 导入copy模块A = ['nupt',56,['I','you','he']]B = copy.deepcopy(A) # 把A浅拷贝给B# 比较A和B的值print A>>>['nupt',56,['I','you','he']]print B >>>['nupt',56,['I','you','he']] # 深拷贝的B,值与A相同# 比较A和B所在的地址print id(A) >>>58888776print id(B) >>>58890824 # 深拷贝的B,地址与A不同# 比较A中的每个元素与B中每个元素的地址print [id(ele) for ele in A]>>>[59288312L,57107912L,58890248L]print [id(ele) for ele in B]>>>[59288312L,57107912L,59327880L] # 深拷贝的B,元素所在地址与A不完全相同# 更改A的值,看B的各项变化A[0] = 'NanJing'A[2].append('she')# 比较A和B的值print A>>>['NanJing',56,['I','you','he' ]]print B >>>['njupt',56,['I','you','he']] # 注意:深拷贝的B,值与A不同# 比较A和B所在的地址print id(A) >>>58888776 # A的地址不变print id(B) >>>58890824 # 深拷贝的B,地址不变,仍与A不同# 比较A中的每个元素与B中每个元素的地址print [id(ele) for ele in A]>>>[59288592L,57107912L,58890248L] # A[0]地址变了,A[2]没变print [id(ele) for ele in B]>>>[59288312L,57107912L,59327880L] # B中每个元素所在地址不变
(2)代码分析
- 首先,创建了一个名为A的变量,这个变量指向一个list对象,变量A及其列表元素所存储的地址如下图:
- 然后,对A指向的对象进行深拷贝,深拷贝会创建一个新对象赋值给B,那么B指向的对象则不是A所指的对象,即:B is not A;
但是深拷贝跟浅拷贝的区别在于:对于对象中的元素,深拷贝都会重新生成一份(有特殊情况,下面会说明),而不是简单的使用原始元素的引用(内存地址)。
比如例子中,B[0] != A[0],B[1]=A[1],B[2]!=A[2] - 接着,变量A的元素发生改变。
A[0]=’NanJing’,A[0]是str类型变量,str是不可变类型,所以修改时会产生一个新对象替换旧对象,也就相应产生一个新地址,id(A[0])改变
A[2].append(‘she’),A[2]是list类型变量,list是可变类型,修改时不会产生新对象,故list本身内存地址不变,即id(A[2])不变: - 但是:由于B[0] != A[0],B[2]!=A[2],so A[0]A[2]的改变对B无影响
4. 注意:
Python中,类型属于对象。如a=23,变量a不是整数型,a仅仅是一个对象的引用(相当于指针),a可以指向list型,可以指向str型。
可变类型的对象:整数、字符串、元组。
如:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变a的值,而是相当于新生成一个a。不可变类型对象: 列表,字典。
如:变量赋值 b=[1,2,3,4] 后再赋值 b[2]=5 则是将 list b的第三个元素值更改,b本身没有动,只是其内部的一部分值被修改了
5. 结论:
- 对于不可变类型的对象:没有拷贝一说。如:浅拷贝/深拷贝时,B[0]=A[0],B[1]=A[1],A[0]A[1]改变,B[0]B[1]都不变
- 对于可变类型的对象:
(1)浅拷贝——指向原对象;原对象内容改变,拷贝对象内容也改变
(2)深拷贝——不指向研对象,重新生成新对象然后赋值给拷贝对象;原对象内容改变,拷贝对象内容不改变
(1)B=A:
B与A值一样,指向的地址一样,内部元素各自地址一样。即:B is A, B[ele] is A[ele]
A的一切元素变,B也变
(2)B=copy.copy(A)
B与A值一样,指向的地址不一样,内部各元素地址一样。即:B is not A, B[ele] is A[ele]
A的“可变类型对象”变,B也变
(3)B=deepcopy(A)
B与A值一样,指向的地址不一样,内部元素地址可能不一样。即:B is not A, B[ele] is not A[ele]
A的“可变类型对象”变,B不变
阅读全文
1 0
- Python —— 深拷贝 VS 浅拷贝
- Python对象拷贝——深拷贝与浅拷贝
- 浅拷贝 vs 深拷贝
- 深拷贝vs浅拷贝
- python学习笔记——浅拷贝与深拷贝
- python之路——深拷贝与浅拷贝
- Python学习笔记——深拷贝与浅拷贝
- Python复制——浅拷贝、深拷贝、切片
- Python——浅拷贝/深拷贝/赋值
- python深拷贝浅拷贝
- python-深拷贝,浅拷贝
- python浅拷贝深拷贝
- python深拷贝浅拷贝
- python浅拷贝 深拷贝
- python 深拷贝&浅拷贝
- python 浅拷贝&深拷贝
- C++之深拷贝VS浅拷贝
- 【JS】深拷贝 vs 浅拷贝
- 单机Redis的安装以及基本操作简介
- Impala 4、Impala JDBC
- poj 1065 Wooden Sticks
- 事件分发和滑动冲突知识点总结
- POJ 1185 炮兵阵地(状压DP)
- Python —— 深拷贝 VS 浅拷贝
- Impala 5、Impala 性能优化
- JAVA环境的配置与安装
- HDU 6070 Dirt Ratio
- HDU-6078 Wavel Sequence(dp+树状数组)
- HDU3342:Legal or Not(拓扑排序)
- I
- 盒子模型和box-sizing属性
- 多个ASP.NET站点如何通过ASP.NET State服务共享Session会话