Python基础【3】:Python中的深浅拷贝解析
深浅拷贝
在研究Python的深浅拷贝区别前需要先弄清楚以下的一些基础概念:
变量--引用--对象(可变对象,不可变对象)
切片(序列化对象)--拷贝(深拷贝,浅拷贝)
我是铺垫~
一、【变量--引用--对象】:
Python中一切皆对象,甚至连type本身都是type对象。
1 >>> type(type(n1))
2 <class 'type'>
Python中的变量不同于与Java/c/c++不同,它是对象的引用,是动态型变量,数据类型无须提前声明,变量类型是根据对象的类型动态变化。
例如运行n=9,Python内部先在内存中找块地址来存储9,n只是对这个对象的引用,或者说将指针指向这个对象。
这里的整数对象9包含了两层含义:
1、数值为9
2、一个头部信息,告诉Python这是个int对象【可理解为一个指向int类型的指针】

小结:
变量是一个系统表的元素,拥有指向对象的连接的空间;
对象是被分配的一块内存,用来存储值;
引用是在变量赋值时自动形成的变量到对象的指针。
再来看下面的例子:
1 >>> a = 3
2 >>> b = a
3 >>> id(a);id(b)
4 1627390480
5 1627390480
6 >>> del a
7 >>> b
8 3 >>> a = 5 >>> b 3


可以看出,a和b共享引用,指向同一个内存地址(其id完全相同),所以将变量a删除或者将a赋值为4,都对变量b的数值无影响。
上面的例子有一个局限,就是数值类型对象是不可改变的,如果换成列表和元组对象呢?
二、【可变对象--不可变对象】
Python中的可变对象:可以修改的对象,列表和字典。
Python中的不可变对象:一旦创建就不可以修改的对象,字符串、元组、整数。
1 >>> L1 = [2,3,4]
2 >>> L2 = L1
3 >>> L2
4 [2, 3, 4]
5 >>> L1= [5,6]
6 >>> L2
7 [2, 3, 4]
8 >>> L1 = [1,2,3]
9 >>> L2 = L1
10 >>> L1[0] = 99
11 >>> L1;L2
12 [99, 2, 3]
13 [99, 2, 3]
14 #因为对象本身变了
如此一来,可变对象的变量共享引用就可能会有问题了(原本对源变量的修改,一不小心影响了其他的变量引用)。所以针对这种情景,才有了深浅copy。
那么如果不想改变上面L2的值有两种作法:切片和copy模块。
1 >>> L1
2 [99, 2, 3]
3 >>> L2 = L1[:]
4 >>> L1,L2
5 ([99, 2, 3], [99, 2, 3])
6 >>> id(L1);id(L2)
7 3089554433480
8 3089554433992
9 >>> L1[0] = 100
10 >>> L1;L2
11 [100, 2, 3]
12 [99, 2, 3]
拷贝
切片技术的应用范围:序列对象,即列表、字符串、元组。
注:序列是一类基本数据类型(字符串/列表/元组)的统称,这些数据类型都含有一些共同的特性。
切片不能应用于字典,对于字典只有dic.copy()方法和dic.deepcopy()方法。
1 >>> dic = {'name':'bolen','age':18}
2 >>> [item for item in dir(dic) if not item.startswith('__')]
3 ['clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']
4
5 #上面的语法和三元运算一样,x = 1 if n >2 else 3(或x = [2,1][n>2]),都是Python中的语法糖。
1 >>> import copy
2 >>> L3 = copy.copy(L1)
3 >>> L4 = copy.deepcopy(L1)
4 >>>
上面铺垫了这么多,就是想说深浅拷贝,既可应用于序列对象也可用于字典。
【浅拷贝】
浅拷贝只拷贝顶层对象或者说父级对象。
【深拷贝】
深拷贝是拷贝所有对象,包括顶级对象和镶套对象,或者说拷贝所有父对象和子对象。
闲言少叙,show code:
1 >>> n1
2 {'k1': 'lilei', 'k3': ['yy', 456], 'k2': 123}
3 >>> n4 = n1
4 >>> n2= copy.copy(n1)
5 >>> n3 = copy.deepcopy(n1)
6 >>> n1;n2;n3;n4
7 {'k1': 'bboo', 'k3': ['yy', 456], 'k2': 123}
8 {'k1': 'bboo', 'k3': ['yy', 456], 'k2': 123}
9 {'k1': 'bboo', 'k3': ['yy', 456], 'k2': 123}
10 {'k1': 'bboo', 'k3': ['yy', 456], 'k2': 123}
11 >>> id(n1);id(n2);id(n3);id(n4)
12 3089553992072
13 3089554432904
14 3089554359368
15 3089553992072
16 #深浅拷贝内存地址和源对象都不一样。
17 >>> n1['k1'] = 'bolen'
18 >>> n1;n2;n3;n4
19 {'k1': 'bolen', 'k3': ['yy', 456], 'k2': 123}
20 {'k1': 'bboo', 'k3': ['yy', 456], 'k2': 123}
21 {'k1': 'bboo', 'k3': ['yy', 456], 'k2': 123}
22 {'k1': 'bolen', 'k3': ['yy', 456], 'k2': 123}
23 >>> n1['k3'][1]=789
24 >>> n1;n2;n3;n4
25 {'k1': 'bolen', 'k3': ['yy', 789], 'k2': 123}
26 {'k1': 'bboo', 'k3': ['yy', 789], 'k2': 123}
27 {'k1': 'bboo', 'k3': ['yy', 456], 'k2': 123}
28 {'k1': 'bolen', 'k3': ['yy', 789], 'k2': 123}
29 #当有多层镶套时,源对象改变后,浅拷贝和共享引用的值都变了,而深拷贝没有变。

【总结】
深浅拷贝都是对源对象的复制,占用不同的内存空间
如果源对象只有一级目录的话,源做任何改动,不影响深浅拷贝对象
如果源对象不止一级目录的话,源做任何改动,都要影响浅拷贝,但不影响深拷贝
序列对象的切片其实是浅拷贝,即只拷贝顶级的对象
Python基础【3】:Python中的深浅拷贝解析的更多相关文章
- python基础知识5——赋值与深浅拷贝——整数和字符串,列表元组字典
深浅copy 一.数字和字符串 对于 数字 和 字符串 而言,赋值.浅拷贝和深拷贝无意义,因为其永远指向同一个内存地址. 1 import copy 2 # ######### 数字.字符串 #### ...
- Core Python Programming一书中关于深浅拷贝的错误
该书关于深浅拷贝的论述: 6.20. *Copying Python Objects and Shallow and Deep Copies "when shallow copies are ...
- python基础-3 集合 三元运算 深浅拷贝 函数 Python作用域
上节课总结 1 运算符 in 字符串 判断 : “hello” in "asdasfhelloasdfsadf" 列表元素判断:"li" in ['li', ...
- 天啦噜!仅仅5张图,彻底搞懂Python中的深浅拷贝
Python中的深浅拷贝 在讲深浅拷贝之前,我们先重温一下 is 和==的区别. 在判断对象是否相等比较的时候我们可以用is 和 == is:比较两个对象的引用是否相同,即 它们的id 是否一样 == ...
- Python 中的深浅拷贝
Python 中的深浅拷贝 参考文献:https://blog.csdn.net/lnotime/article/details/81194633 参考文献:https://blog.csdn.net ...
- 二十一. Python基础(21)--Python基础(21)
二十一. Python基础(21)--Python基础(21) 1 ● 类的命名空间 #对于类的静态属性: #类.属性: 调用的就是类中的属性 #对象.属性: 先从自己的内存空间里找名 ...
- js中的深浅拷贝
js中的深浅拷贝 js中有深拷贝.浅拷贝一说,所谓的深浅拷贝是针对value类型为引用类型(函数.对象.数组)而言的,大概理解的就是: 浅拷贝: 拷贝出的对象c和原始对象o,c和o在key对应的val ...
- Python中的深浅拷贝
1.什么是深浅拷贝? python中一切皆对象,python中的数字.字符串.元组等,如果存放在了内存中,这部分内存里面的内容是不会改变的,但是也有情况,内存中存放了可变对象,比如说列表和字典,他们的 ...
- Python中的深浅拷贝,赋值及引用
简单来说,若对象a中存的是列表或字典等可变对象,b对a的浅拷贝只是对对象第一层的复制,修改b第二层的元素仍然会影响两个对象. 深拷贝则是不会影响原来的对象. import copy.copy() 浅拷 ...
随机推荐
- [NOI2018]归程 kruskal重构树
[NOI2018]归程 LG传送门 kruskal重构树模板题. 另一篇文章里有关于kruskal重构树更详细的介绍和更板子的题目. 题意懒得说了,这题的关键在于快速找出从查询的点出发能到达的点(即经 ...
- Java并发工具类(三):控制并发线程数的Semaphore
作用 Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源. 简介 Semaphore也是一个线程同步的辅助类,可以维护当前访问自身的线程个数 ...
- setjmp/longjmp 处理异常
#include <stdio.h> #include <stdlib.h> #include <setjmp.h> jmp_buf jb; void f1() { ...
- Android Studio 重命名文件
选中文件,Refactor——Rename AS提供了两种方式重命名,Rename 和 Rename File,暂时还不清楚区别.有知道的麻烦告知下.
- grads,fortran,ncl二进制文件
#转自论坛日志# grad用fwrite生成的二进制文件大小和ncl用fbinwrite生成的不一样,相差有8个字节,参考了以下网页,问题出在顺序存取和直接存取的差异. 以下是我的理解,欢迎指正: ...
- appium 元素定位方法汇总
以上图为例,要定位到右下角的 我的 ,并点击 # appium的webdriver提供了11种元素定位方法,在selenium的基础上扩展了三个,可以在pycharm里面输入driver.find_e ...
- 关于MySql数据库主键及索引的区别
一.什么是索引?索引用来快速地寻找那些具有特定值的记录,所有MySQL索引都以B-树的形式保存.如果没有索引,执行查询时MySQL必须从第一个记录开始扫描整个表的所有记录,直至找到符合要求的记录.表里 ...
- 关于几个与IO相关的重要概念
1.读/写IO 读IO就是发指令从磁盘读取某段序号连续的扇区内容.指令一般是通知磁盘开始扇区位置,然后给出需要从这个初始扇区往后读取的连续扇区个数,同时给出动作是读还是写.磁盘收到这条指令就会按照指令 ...
- VMware两台虚拟机之间文件共享
虚拟机A的文件拷贝到虚拟机B scp[参数][原路径][目标路径] eg: scp -r root@192.168.0.172:/home/rookie/下载/ /home/rooookie/下载/ ...
- PASSWORD MySQL 5.6.21-1ubuntu14.04_amd64
/***************************************************************************** The main idea is that ...