Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >拷贝有深浅,复制需谨慎

拷贝有深浅,复制需谨慎

作者头像
皮大大
发布于 2021-03-01 08:32:18
发布于 2021-03-01 08:32:18
43100
代码可运行
举报
运行总次数:0
代码可运行

拷贝有深浅,复制需谨慎

在很多语言中都存在深浅拷贝两种拷贝数据的方式,Python中也不例外。本文中详细介绍了Python中的深浅拷贝的相关知识,文章的内容包含:

  • 对象、数据类型、引用
  • 赋值
  • 浅拷贝
  • 深拷贝

Python对象

我们经常听到:在Python中一切皆对象。其实,说的就是我们在Python中构造的任何数据类型都是一个对象,不管是数字、字符串、字典等常见的数据结构,还是函数,甚至是我们导入的模块等,Python都会把它当做是一个对象来处理。

所有的Python对象都拥有3个属性:

  • 身份
  • 类型

我们看一个简单的例子来理解上面的3个属性:

假设我们声明了一个name变量,通过id、type方法能够查看对象的身份和类型:

甚至是type本身也是一个对象,它也拥有自己的身份、类型:

Python中,万物皆对象

数据类型

在Python中,按照更新对象的方式,我们可以将对象分为2大类:可变数据类型不可变数据类型

  • 不可变数据类型:数值、字符串、布尔值。不可变对象就是对象的身份和值都不可变。新创建的对象被关联到原来的变量名,旧对象被丢弃,垃圾回收器会在适当的时机回收这些对象。
  • 可变数据类型:列表、字典、集合。所谓的可变指的是可变对象的值可变,但是身份是不可变的。

1、首先我们看看不可变对象:

当我们定义了一个对象str1,给其赋值了“Python”,便会在内存中找到一个固定的内存地址来存放;但是,当我们将“Python”定义成另一个变量名的时候,我们发现:它在内存中的位置是不变的

也就是说,这个变量在计算机内存中的位置是不变的,只是换了一个名字来存放,来看3个实际的例子:

以上的例子说明:当我们对字符串、数值型、布尔值的数据改变变量名,并不会影响到数据在内存中的位置。

2、我们看看可变类型的例子:

列表、字典、集合都是一样的效果:

虽然是相同的数据,但是变量名字不同,内存中仍然会开辟新的内存地址来进行存放相同的数据,我们以字典为例:

引用

在Python语言中,每个对象都会在内存中申请开辟一块新的空间来保存对象;对象在内存中所在位置的地址称之为引用。

可以说,我们定义的变量名实际上就是对象的地址引用。引用实际上就是内存中的一个数字地址编号。在使用对象的时候,只要知道这个对象的地址,我们就可以操作这个对象。

因为这个数字地址不太容易记忆,所以我们使用变量名的形式来代替对象的数字地址。在Python中,变量就是地址的一种表示形式,并不会开辟新的存储空间。

我们通过一个例子来说明变量和变量指向的引用(内存地址)实际上就是一个东西:

赋值

相同数据,不同变量名

讨论完Python的对象、属性和引用3个重要的概念之后,在正式介绍深浅拷贝之前,我们先讨论Python中的赋值

在Python中,每次赋值都会开辟新的内存地址来存放数据,比如我们同时存放一个列表[1,2,3],即使数据是相同的,但是内存地址却不同:

其实就是两个不同的变量,只是恰好它们存放了相同的数据而已,但是存放的地址是不同的。

我们给v1列表追加了一个元素,发现它的内存地址是不变的,当然v2肯定是不变的:

一个变量多次赋值

如果我们对一个变量多次赋值,其内存是会变化的:

变量赋值

将一个变量赋值给另一个变量,其实它们就是同一个对象:数据相同,在内存中的地址也相同:

当我们给V1追加一个元素,V2也会同时变化:

实际上它们就是同一个对象!!!!

嵌套赋值

如果是列表中嵌套着另外的列表,那么当改变其中一个列表的时候,另一个列表中的也会随着改变:

原始数据信息:

当我们给v1追加了新元素之后:

总结:赋值其实就是将一个对象的地址赋值给一个变量,使得变量指向该内存地址。

浅拷贝

在Python中进行拷贝之前,我们需要导入模块:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import copy

⚠️浅拷贝只是拷贝数据的第一层,不会拷贝子对象

不可变类型的浅拷贝

如果只是针对不可变的数据类型(字符串、数值型、布尔值),浅拷贝的对象和原数据对象是相同的内存地址:

从上面的结果中我们可以看出来:针对不可变类型的浅拷贝,只是换了一个名字,对象在内存中的地址其实是不变的。

可变类型的浅拷贝

1、首先我们讨论的是不存在嵌套类型的可变类型数据(列表、字典、集合)

从上面的例子看出来:

  • 列表本身的浅拷贝对象的地址和原对象的地址是不同的,因为列表是可变数据类型
  • 列表中的元素(第1个元素为例)和浅拷贝对象中的第一个元素的地址是相同的,因为元素本身是数值型,是不可变的

通过一个图形来说明这个关系:

字典中也存在相同的情况:字典本身的内存地址不同,但是里面的键、值的内存地址是相同的,因为键值都是不可变类型的数据。

2、如果可变类型的数据中存在嵌套的结构

从上面的两个例子中我们可以看出来:

在可变类型的数据中,如果存在嵌套的结构类型,浅拷贝只复制最外层的数据,导致内存地址发生变化,里面数据的内存地址不会变

深拷贝

深拷贝不同于浅拷贝的是:深拷贝会拷贝所有的可变数据类型,包含嵌套的数据中的可变数据

深拷贝是变量对应的值复制到新的内存地址中,而不是复制数据对应的内存地址

不可变类型的深拷贝

关于不可变类型的深浅拷贝,其效果是相同的,具体看下面的例子:

我们得出一个结论:

针对不可变数据类型的深浅拷贝,其结果是相同的

可变类型的深拷贝

1、首先我们讨论的是不存在嵌套的情况:

针对列表数据

针对字典数据

我们可以得出结论:

1、 深拷贝对最外层数据是只拷贝数据,会开辟新的内存地址来存放数据

2、深拷贝对里面的不可变数据类型直接复制数据和地址,和可变类型的浅拷贝是相同的效果

2、我们讨论存在嵌套类型的深拷贝(以列表为例)

结论1:对整个存在嵌套类型的数据进行深浅拷贝都会发生内存的变化,因为数据本身是可变的

结论2:我们查看第一个元素1的内存地址,发生三者是相同的,因为1是属于数值型,是不可变类型

结论3:我们查看第三个元素即里面嵌套列表的内存,发现只有深拷贝是不同的,因为这个嵌套的列表是可变数据类型,深拷贝在拷贝了最外层之后还会继续拷贝子层级的可变类型

结论4:我们查看嵌套列表中的元素的内存地址,发现它们是相同的,因为元素是数值型,是不可变的,不受拷贝的影响

总结

通过大量的例子,我们得出结论:

  • 浅拷贝只会拷贝最外层的数据
  • 深拷贝会拷贝所有层级的可变类型数据
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-11-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Python深浅拷贝
对于字符串str、整数型int、布尔值bool三种不可变的对象类型,深浅拷贝是一样的,直接在内存中直接开辟空间进行存储。
皮大大
2021/03/02
3830
搞定面试之图解Python深拷贝浅拷贝
「引用」:在 Python 程序中,每个对象都会在内存中申请开辟一块空间来保存该对象,该对象在内存中所在位置的地址被称为引用,使用变量名进行指代。
吾非同
2021/01/06
4200
Python基础 | 深浅拷贝问题、递归函数练习
在实际工作中,经常涉及到数据的传递,在数据传递使用过程中,可能会发生数据被修改的问题。为了防止数据被修改,就需要在传递一个副本,即使副本被修改,也不会影响原数据的使用。为了生成这个副本,就产生了拷贝。下面先了解一下几个概念:对象、可变类型、引用
叶庭云
2021/12/07
4930
Python基础 | 深浅拷贝问题、递归函数练习
python学习笔记:深浅拷贝的使用和原理
在理解深浅拷贝之前,我们先熟悉下变量对象和数据类型 1.变量和对象 变量-引用-对象(可变对象,不可变对象) 在python中一切都是对象,比如[1,2],'hello world',123,{'k1
用户1679793
2018/04/28
7290
python学习笔记:深浅拷贝的使用和原理
python基础之深浅copy
首先在了解python中的深浅拷贝之前,我们先花一点时间来了解一下python内存中变量的存储情况。对于python而言,变量的存储采用了引用语义的方式,存储的只是一个变量值所在的内存地址,而不是这个变量的本身。
天钧
2019/07/26
3840
一、python学习笔记-基本数据类型-深浅拷贝(一)
"""定义 在Python中对象的赋值其实就是对象的引用。当创建一个对象,把它赋值给另一个变量的时候,python并没有拷贝这个对象,只是拷贝了这个对象的引用而已。 浅拷贝:拷贝了最外围的对象本身,内部的元素都只是拷贝了一个引用而已。也就是,把对象复制一遍,但是该对象中引用的其他对象我不复制(快捷方式) 深拷贝:外围和内部元素都进行了拷贝对象本身,而不是引用。也就是,把对象复制一遍,并且该对象中引用的其他对象我也复制。(复制) """ """术语解释 1、变量:是一个系统表的元素,拥有指向对象的连接空间
堕落飞鸟
2022/01/12
2660
​深度解析Python的赋值、浅拷贝、深拷贝
拷贝 就是把原数据复制一份,在复制的数据上随意改动不会影响到其原数据。也就是这里讲的深拷贝。
忆想不到的晖
2021/04/04
5K0
python高级-深浅拷贝(16)
一、浅拷贝 浅拷贝是对一个对象的顶层拷贝,通俗地讲就是:拷贝了引用,并没有拷贝内容。 a = [1,2,3] print(id(a)) b=a print(b) print(id(b)) a.append(4) print(a) print(b) 运行结果为: 1965053928072 [1, 2, 3] 1965053928072 [1, 2, 3, 4] [1, 2, 3, 4] 二、深拷贝 深拷贝是对于一个对象所有层次的拷贝,重新开辟内存地址。 import copy a = [1,2,3] pr
Se7eN_HOU
2019/09/11
3140
Python | Python学习之深浅拷贝
== 是 python 标准操作符中的比较操作符,用来比较判断两个对象的 value(值) 是否相等 。
咸鱼学Python
2019/10/09
4410
Python | Python学习之深浅拷贝
元组、字典、集合的内置方法,散列表、深浅拷贝学习笔记
元组的使用方法(与列表类似):索引取值、索引切片、for循环、成员运算、index获取元素索引、count计数
GH
2022/05/10
3190
元组、字典、集合的内置方法,散列表、深浅拷贝学习笔记
Python深浅拷贝
深浅拷贝分为两部分,一部分是数字和字符串另一部分是列表、元组、字典等其他数据类型。
py3study
2020/01/15
4020
day06(深浅拷贝,元组,字典,集合)
1,今日内容: 1.深浅拷贝:**** 2.元组 - 元组可以存放可变类型 *** 3.字典:***** -- 增删改查 -- 常用方法 4.集合:** -- 集合运算 5.数据类型的相互转化 ******** 6.内存管理 ***** 二,深浅拷贝 ## 拷贝:对值进行复制的过程 # 1,值拷贝:应用场景最多 ls = [1, 'abc', [10]] ls1 = ls # ls1直接将ls中存放的地址拿过来 # ls内部的值发生任何变化,ls1都会随之变化 #2,浅拷贝
py3study
2020/01/16
3750
深拷贝和浅拷贝原来是这样?
为了让读者更好的理解深浅拷贝,在讲深浅拷贝之前要引入基本数据类型 , 引用数据类型 和 数据储存(栈和堆)这几个概念,如果已经理解,可直接跳过这一part。
IT人一直在路上
2019/09/16
4140
由问题入手,步步爬出Python中赋值与拷贝的坑
1、问题的引出 之前遇到了一个求数组中出现次数最多的k个元素的题,我们参照如下的思路进行求解,首先利用一个dict记录所有元素出现的次数,key:value中的key表示元素,value表示元素出现的次数,随后根据元素出现的次数将元素放入对应的桶中,桶是一个二维数组,桶中第一个元素保存出现次数为0的元素,桶中第二个元素保存出现次数为1的元素,依次类推。最后从后往前遍历桶,取出出现次数最多的k个元素即可。 按照这样的思路,我写了如下的代码: class Solution(object): def to
石晓文
2018/04/11
9240
由问题入手,步步爬出Python中赋值与拷贝的坑
JS复习之深浅拷贝
  想掌握JS的深浅拷贝,首先来回顾一下JS的数据类型,JS中数据类型分为基本数据类型和引用数据类型。
huofo
2022/03/18
3980
JS复习之深浅拷贝
js数组的拷贝赋值复制-你真的懂?
在看react-native性能优化的时候,看到如何避免shouldComponentUpdate的异常数据时,脑内一阵风暴,从而牵连出一连串的问题,于是有了这一篇关于js数组的复制(深浅拷贝)与赋值等为何能产生异常数据的文章。 有什么问题欢迎指正 现在进入正题: 首先异常数据的产生在于我们在复制赋值时,会有或没有改变到本身的值。 一、push与concat push的定义是:像数组末尾添加一个或更多元素,并返回新的长度。该方法会改变数组的长度。 concat的定义是:连接两个或更多的数组,并返回结果,该方
IT架构圈
2018/05/31
4.9K0
python学习笔记:第7天 深浅拷贝
join方法是把一个列表中的数据进行拼接,拼接成字符串(与split方法相反,split方法是把一个字符串切割成列表)
py3study
2020/01/20
4160
学习Python一年,这次终于弄懂了浅拷贝和深拷贝
话说,网上已经有很多关于Python浅拷贝和深拷贝的文章了,不过好多文章看起来还是决定似懂非懂,所以决定用自己的理解来写出这样一篇文章。
宇宙之一粟
2020/10/26
6980
学习Python一年,这次终于弄懂了浅拷贝和深拷贝
Python|赋值、浅拷贝与深拷贝
在python中一个变量可以说是内存中一个对象的‘标签’或者‘引用’。假设现在有一个变量a。
算法与编程之美
2019/07/17
7120
Python基础三
不可变的数据类型公用,可变的数据类型重新开辟一个空间,对源数据进行修改,深拷贝的内容不进行改变
changxin7
2019/09/10
1.4K0
相关推荐
Python深浅拷贝
更多 >
领券
💥开发者 MCP广场重磅上线!
精选全网热门MCP server,让你的AI更好用 🚀
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验