前言
在很多语言中都存在深浅拷贝两种拷贝数据的方式,Python中也不例外。本文中详细介绍了Python中的深浅拷贝的相关知识,文章的内容包含:- 对象、数据类型、引用
- 赋值
- 浅拷贝
- 深拷贝
![d9e68f831919da09a4862874507dec05.png](https://i-blog.csdnimg.cn/blog_migrate/635112d198cefbb990ccf90ef9330de4.jpeg)
一、Python对象
我们经常听到:在Python中一切皆对象。其实,说的就是我们在Python中构造的任何数据类型都是一个对象,不管是数字、字符串、字典等常见的数据结构,还是函数,甚至是我们导入的模块等,Python都会把它当做是一个对象来处理。 所有的Python对象都拥有3个属性:- 身份
- 类型
- 值
![ba678e4f63a7c9c013983f3b9a6012a3.png](https://i-blog.csdnimg.cn/blog_migrate/cf5c79d11c1e5b6901b68221d5321ae8.jpeg)
![1405d054df074acd90db80d3b7df6ab7.png](https://i-blog.csdnimg.cn/blog_migrate/ec529f1dc1738e22121add477f362010.jpeg)
Python中,万物皆对象
二、数据类型
2.1 可变和不可变类型
在Python中,按照更新对象的方式,我们可以将对象分为2大类:可变数据类型和不可变数据类型。- 不可变数据类型:数值、字符串、布尔值。不可变对象就是对象的身份和值都不可变。新创建的对象被关联到原来的变量名,旧对象被丢弃,垃圾回收器会在适当的时机回收这些对象。
- 可变数据类型:列表、字典、集合。所谓的可变指的是可变对象的值可变,但是身份是不可变的。
![808a66e4187b1042264bd809e6893316.png](https://i-blog.csdnimg.cn/blog_migrate/2e30c4501e21ddc3394bdbbbc9e146ba.jpeg)
![682e154024aa0f213a6c0d601258228f.png](https://i-blog.csdnimg.cn/blog_migrate/26507be1e690f716392a9eb0a7ecbeaf.jpeg)
![e6c2f3f9f493045fc04190828d9e153a.png](https://i-blog.csdnimg.cn/blog_migrate/d8374eec5fd9b33a96a10969b5f22bb5.jpeg)
![c853ac74425c197705137780e597a0e4.png](https://i-blog.csdnimg.cn/blog_migrate/5467a4cbebc1b19a606cacb8f9fe0577.jpeg)
![a297426e39b4020a89acce02fae89540.png](https://i-blog.csdnimg.cn/blog_migrate/d7fdc559a5eb69169106bac4615bbbe5.jpeg)
![304f01d1672091ca731b26c3ed3fb127.png](https://i-blog.csdnimg.cn/blog_migrate/32af0e309abaa66f2c8c7d2c2d5baf9b.jpeg)
![f400a6322bddeb9da03eb7d61399e060.png](https://i-blog.csdnimg.cn/blog_migrate/1d115ecb18855ed2bae17568b538f0a7.jpeg)
![5c6a28d420a9695b6116371033d83215.png](https://i-blog.csdnimg.cn/blog_migrate/215fd051aaf7fa3dfc79ec56bb44ce79.jpeg)
![52986e17d2be17e5d513a7e846fd99c8.png](https://i-blog.csdnimg.cn/blog_migrate/298e5cc6dea05337931f183f26fe5a62.jpeg)
2.2 引用
在Python语言中,每个对象都会在内存中申请开辟一块新的空间来保存对象;对象在内存中所在位置的地址称之为引用。 可以说,我们定义的变量名实际上就是对象的地址引用。引用实际上就是内存中的一个数字地址编号。在使用对象的时候,只要知道这个对象的地址,我们就可以操作这个对象。 因为这个数字地址不太容易记忆,所以我们使用变量名的形式来代替对象的数字地址。在Python中,变量就是地址的一种表示形式,并不会开辟新的存储空间。 我们通过一个例子来说明变量和变量指向的引用(内存地址)实际上就是一个东西:![6c5a9eb8a2f114703f07663a7845ef5a.png](https://i-blog.csdnimg.cn/blog_migrate/131126e569b656c2d01a37064ce7d874.jpeg)
![2be7a5583e8f500bb27afd697e4f0872.png](https://i-blog.csdnimg.cn/blog_migrate/a00056c5ccc7644f28f969fad0413e22.jpeg)
三、赋值
3.1 相同数据,不同变量名
讨论完Python的对象、属性和引用3个重要的概念之后,在正式介绍深浅拷贝之前,我们先讨论Python中的赋值。 在Python中,每次赋值都会开辟新的内存地址来存放数据,比如我们同时存放一个列表[1,2,3],即使数据是相同的,但是内存地址却不同:![7cba7cbf1ebf532258e2cc96a5db727a.png](https://i-blog.csdnimg.cn/blog_migrate/93ae0f933a2e5cfa706380f06af14166.jpeg)
![cc675c6f8f920d470dfc000cda9b483c.png](https://i-blog.csdnimg.cn/blog_migrate/6b0b18c0a4da0f1fb2a2289777771cc0.jpeg)
![918047dbf9820c556702fca76725c44c.png](https://i-blog.csdnimg.cn/blog_migrate/32c363175f8879783b71650b65a4230b.jpeg)
![f7c9e7f79d51d558af98d2a192c2ecdc.png](https://i-blog.csdnimg.cn/blog_migrate/f35688af1d44f4f6fff6e7b17c38227c.jpeg)
3.2 一个变量多次赋值
如果我们对一个变量多次赋值,其内存是会变化的:![800c0737cf347daa0ccb3b3d036fd11d.png](https://i-blog.csdnimg.cn/blog_migrate/6de4edaa1d3aefe5d3610d2c455503f5.jpeg)
![ca57770c93461b1545ba28c856dc97d1.png](https://i-blog.csdnimg.cn/blog_migrate/0b6d489931ad4bf708438e78eac7f7b7.jpeg)
3.3 变量赋值
将一个变量赋值给另一个变量,其实它们就是同一个对象:数据相同,在内存中的地址也相同:![706cabb0c0441b0b92b22df030b9156b.png](https://i-blog.csdnimg.cn/blog_migrate/74b3a67f6d265945b2b915e965cc9f55.jpeg)
![252395034b1ba18b3fafbfe03905f86c.png](https://i-blog.csdnimg.cn/blog_migrate/48f1e6574a7306bfb2341cf516f27e27.jpeg)
![6993c72465a0c3fc84260fcf57906f44.png](https://i-blog.csdnimg.cn/blog_migrate/992e1091b4ecf3691707bd958aa8d6da.jpeg)
3.4 嵌套赋值
如果是列表中嵌套着另外的列表,那么当改变其中一个列表的时候,另一个列表中的也会随着改变:![2eb2cd01b003ded4187c5a3a0956a1a2.png](https://i-blog.csdnimg.cn/blog_migrate/27e00dc3ef74724205ce484a168e9708.jpeg)
![2f10c4a5ea4f6ccf81948a205ba1af2f.png](https://i-blog.csdnimg.cn/blog_migrate/f2f0fb9bd04bcbe3e3e64e8cf53927aa.jpeg)
![c2971e13fc348c5579e1017cd99b8453.png](https://i-blog.csdnimg.cn/blog_migrate/c4756169a32d0473db7cc11b33a1fd29.jpeg)
四、浅拷贝
在Python中进行拷贝之前,我们需要导入模块:
import copy
⚠️浅拷贝只是拷贝数据的第一层,不会拷贝子对象。
4.1 不可变类型的浅拷贝
如果只是针对不可变的数据类型(字符串、数值型、布尔值),浅拷贝的对象和原数据对象是相同的内存地址:![96c2b3c63c5b1ecc4ee7677737c4d1cd.png](https://i-blog.csdnimg.cn/blog_migrate/a26e3288cfa8f23914ee70a7361300c8.jpeg)
![d3035aa4d17f3c713b6d0ced7f5be912.png](https://i-blog.csdnimg.cn/blog_migrate/a8a4e866700a8ca847bfd61e98125e69.jpeg)
![3521ac813162df74c4ca2bbac7d36dff.png](https://i-blog.csdnimg.cn/blog_migrate/79b36e4a4e5adfdbf772a5f2f5f730f1.jpeg)
image-20201115225938833
4.2 可变类型的浅拷贝
首先我们讨论的是不存在嵌套类型的可变类型数据(列表、字典、集合):![237911e33d1ab32580d56a1fb08b6f7a.png](https://i-blog.csdnimg.cn/blog_migrate/fc226c12c5a7825f1549b4585e8f84b1.png)
- 列表本身的浅拷贝对象的地址和原对象的地址是不同的,因为列表是可变数据类型。
- 列表中的元素(第1个元素为例)和浅拷贝对象中的第一个元素的地址是相同的,因为元素本身是数值型,是不可变的。
![c9a37eafc8cf3ab5aa6b0b646ea754e2.png](https://i-blog.csdnimg.cn/blog_migrate/9390fd01975fd975c3a33e85e95ae88f.jpeg)
![3fd1fe88649ccdebdc6461f015a84a5d.png](https://i-blog.csdnimg.cn/blog_migrate/bfcb8ac1a5b1b8f6dd55eed194a8367e.jpeg)
![1d827e3ffd76d9c563b914e7afdf59e0.png](https://i-blog.csdnimg.cn/blog_migrate/967dfbfdcb30079528a68d3cac56f12c.jpeg)
五、深拷贝
深拷贝不同于浅拷贝的是:深拷贝会拷贝所有的可变数据类型,包含嵌套的数据中的可变数据。深拷贝是变量对应的值复制到新的内存地址中,而不是复制数据对应的内存地址。5.1 不可变类型的深拷贝
关于不可变类型的深浅拷贝,其效果是相同的,具体看下面的例子:![e7bc36fa4c60b97bd097108032c064cc.png](https://i-blog.csdnimg.cn/blog_migrate/b7b5790393f94ebf7b6620fa5e9e0860.jpeg)
![c06de31c9dfe764b393f761389873fca.png](https://i-blog.csdnimg.cn/blog_migrate/67050bd2bdd7ad83da4b2f87563ddf62.jpeg)
![c4b5714b82371449f5969d17b31c439d.png](https://i-blog.csdnimg.cn/blog_migrate/15c0d021bc72da50f3b0d3c82c1796ec.jpeg)
5.2 可变类型的深拷贝
首先我们讨论的是不存在嵌套的情况: 针对列表数据:![0d8d9512abdbfa677fcb0fe64dc0bc5b.png](https://i-blog.csdnimg.cn/blog_migrate/e140c7ccabbd08d0e2c468d66959e307.jpeg)
![e06d3fd10e3e627b7c64635dbbcf707a.png](https://i-blog.csdnimg.cn/blog_migrate/25e74cbb486645fd15dbe80bf11325c6.jpeg)
![55f4bb9159d75691aea9d13e72a986ab.png](https://i-blog.csdnimg.cn/blog_migrate/2862223cf3fb3528b14a3328c4cb66f2.jpeg)
![2c1d263d0b51f064ef26f96cc1154bf1.png](https://i-blog.csdnimg.cn/blog_migrate/55d9e62aaeed766df340e595670ffbe7.jpeg)
- 深拷贝对最外层数据是只拷贝数据,会开辟新的内存地址来存放数据。
- 深拷贝对里面的不可变数据类型直接复制数据和地址,和可变类型的浅拷贝是相同的效果。
![c8ffb51efc34892f2a31d8d55c01013c.png](https://i-blog.csdnimg.cn/blog_migrate/9c2632b760ebebda169f656f8dd698a6.jpeg)
![db1d09500fba71433de712ab127d63a9.png](https://i-blog.csdnimg.cn/blog_migrate/fb43d3008a15b92be23d49d125a26c8a.jpeg)
![e59499c9fe98784c42d8b69b5b4a2e8f.png](https://i-blog.csdnimg.cn/blog_migrate/b2b28615b8dc7e19cba57d022049c69f.jpeg)
![a8307965ef98ca314cfe346f14157488.png](https://i-blog.csdnimg.cn/blog_migrate/8e52e633bef225980badae8bd9ae110b.jpeg)
![0977f8cb0d3d76e83885262e5a4753e3.png](https://i-blog.csdnimg.cn/blog_migrate/3ee68dfdedbff69c2cb90fa07c1bc0a2.jpeg)
六、元组的深浅拷贝
元组本身是不可变数据类型,但是其中的值是可以改变的,内部可以有嵌套可变数据类型,比如列表等,会对它的拷贝结果造成影响。6.1 不存在嵌套结构
当元组中不存在嵌套结构的时候,元组的深浅拷贝是相同的效果:![7720b4ca5fc253454484cf1bfe131563.png](https://i-blog.csdnimg.cn/blog_migrate/e590bcc3ae57312bd459db213c108a1f.jpeg)
6.2 存在嵌套结构
当元组的数据中存在嵌套的可变类型,比如列表等,深拷贝会重新开辟地址,将元组重新成成一份。![2ad253c628251f6f913ad5dfad1eb495.png](https://i-blog.csdnimg.cn/blog_migrate/4420e8040d5c6fcdfb8d4cee8b8b3056.jpeg)
七、is和==
在文章的开始就已经谈过:在Python中每个变量都有自己的标识、类型和值。每个对象一旦创建,它的标识就绝对不会变。一个对象的标识,我们可以理解成其在内存中的地址。is()运算符比较的是两个对象的标识;id()方法返回的就是对象标识的整数表示。 总结:is()比较对象的标识;==运算符比较两个对象的值(对象中保存的数据)。在实际的编程中,我们更多关注的是值,而不是标识本身。 第一个例子:我们创建了两个不同的对象,只是它们的值刚好相同而已。![472de698d361aa32bfdc65710ac377f6.png](https://i-blog.csdnimg.cn/blog_migrate/c13a4484514b40b2547765bb65d51d32.jpeg)
![19f96a983309e71fca92fdac2679ad37.png](https://i-blog.csdnimg.cn/blog_migrate/2597ac97af0ffad478c7eed38e439af8.jpeg)
![cfe737b08827bcccacbc0fc9bf35fd51.png](https://i-blog.csdnimg.cn/blog_migrate/8d8b4c25bd76e136f93b137fe7ef8b02.jpeg)
![7f63d5e6f6ee0298b3b6d8aa94ecb4cd.png](https://i-blog.csdnimg.cn/blog_migrate/7df86dd368bcff47c29dd20ff5904d99.jpeg)
总结
通过大量的例子,我们得出结论:- 在不可变数据类型中,深浅拷贝都不会开辟新的内存空间,用的都是同一个内存地址。
- 在存在嵌套可变类型的数据时,深浅拷贝都会开辟新的一块内存空间;同时,不可变类型的值还是指向原来的值的地址。
转自:Datawhale;
END版权声明:本号内容部分来自互联网,转载请注明原文链接和作者,如有侵权或出处有误请和我们联系。
合作请加QQ:365242293
数据分析(ID : ecshujufenxi )互联网科技与数据圈自己的微信,也是WeMedia自媒体联盟成员之一,WeMedia联盟覆盖5000万人群。