Python可变与不可变数据和深拷贝与浅拷贝
作者:小可爱呦 发布时间:2022-06-05 21:14:51
浅拷贝和深拷贝
拷贝函数是专门为可变数据类型list、set、dict使用的一种函数。作用是,当一个值指向另一个值的时候,也不会影响指向的值,如果被指向的数据是可变数据,那么它一旦被修改,指向的数据也会随之改变。
什么是可变数据和不可变数据
我们来举一个例子,整型是不可变的数据,那么为什么是不可变的数据呢?一个数据是不是可变的就要关系到python的缓存机制。
当一个数据发生变化,如果它的内存地址没有发生变化,就说明这是一个可变数据。
比如说,我们现在创建一个值是a的变量,它的值是100,然后让这个数值发生变化,观察者个变量的内存地址是否发生了变化。
a = 100
print(a, id(a)) # 100 1610845392
a += 100
print(a, id(a)) # 200 1610848592
我们发现数值发生了变化,变量的内存也跟着发生了变化,我们再创建一个变量b,值也是整型100
b = 100
print(b, id(b))# 100 1610845392
发现b的内存地址和a的内存地址是一样的,也就是说,像整型这样的数据类型,一个数字就独占一个内存地址,当某个指向这个值的变量,发生了变化的时候,不是这个变量的值要改变,而是这个变量要寻找改变后的值的内存地址,然后重新的指向它。只要你的硬件不重新启动,那么这个内存地址就永远也不会发生变化了,这样的数据就是不可变数据。
那么,反之就是可变数据,指的就是当变量指向的值发生变化之后,在这个内存地址上的值实打实的发生变化的值,就是可变数据类型。
比如列表,列表发生改变之后,是在原有的基础上发生变化的,所以内存地址是不会改变的,这就是可变数据类型,可变数据类型没有内存缓存机制,不能节省内存,所以一模一样的数据,他们的内存地址可能是不相同的。
a = [1, 2]
print(a, id(a)) # [1, 2] 1528536069896
a.append(3)
print(a, id(a)) # [1, 2, 3] 1528536069896
# b 和 a的值相同,但是内存地址不相同
b = [1, 2, 3]
print(b, id(b)) # [1, 2, 3] 1528536069832
那么拷贝函数是干什么的?
在我们的实际工作当中,经常会使用的一种操作就是定义一个变量,它的值直接就赋给了一个原有的变量之上。可是变量定义之后我们绝不是用来作为一个摆设的,而是要做运算、或者是做一个临时的存储,那么原有的变量的值是要改变的,问题就来了,如果是一个不可变的数据还好,如果是可变的数据,直接的赋值他们的内存地址是相同的, 如果一个变量的值发生变化,同内存地址的的值就都发生改变了,我们的向要临时存储的值也就不再是我们想要的那个值了,这是绝大多数的时候我们不想看到的结果。
我们拿整型为例,变量a直接赋值给变量b,这个时候的变量a b 的值是相同的,但是如果变量a的值发生了变化,是丝毫不影响变量b的值的。
a = 100
print(a, id(a)) # 100 1610845392
b = a
print(b, id(b)) # 100 1610845392
a += 100
print(a, id(a)) # 200 1610848592
print(b, id(b)) # 100 1610845392
但是如果是可变数据就不是这样的情况了
a = [1, 2]
print(a, id(a)) # [1, 2] 2077688035080
b = a
print(b, id(b)) # [1, 2] 2077688035080
a.append(3)
print(a, id(a)) # [1, 2, 3] 2077688035080
print(b, id(b)) # [1, 2, 3] 2077688035080
不可变数据的这个特性既是一个优点也是一个缺点,缺点就是如果我们想要保存a变量发生变化之前的的一个状况的时候,是保存不下来的,这个时候就出现了拷贝函数,它可以将可变数据变成不可变数据那样的效果。
浅拷贝
使用拷贝函数,将a变量放入作为参数放入函数中,使用b变量接受函数的返回值,就成功的拷贝了变量a,变量b的内存地址和变量a的不一样,这样当它们其中一方发生变化之后,不会影响到另一方的数据。
# 拷贝函数不能直接使用,需要使用import导入copy模块,copy模块的copy函数就是浅拷贝
import copy
a = [1, 2, 3]
# 变量b不在直接是变量a的直接赋值了,而是通过copy函数的返回值
b = copy.copy(a)
# 他们的数值一样,但是内存地址不同,所以他们之间的任意一方发生变化都不会影响到第二方。
print(a, id(a)) # [1, 2, 3] 2343743813320
print(b, id(b)) # [1, 2, 3] 2343743813192
a.append(4)
print(a, id(a)) # [1, 2, 3, 4] 2343743813320
print(b, id(b)) # [1, 2, 3] 2343743813192
但是如果变量a是一个二级容器或者是一个更多级容器,浅拷贝无法拷贝第二级容器或者更多级的容器,所以当第二级容器或者是更多级的容器发生变化的时候,还是会发生变化,因为浅拷贝只能拷贝一级容器,所以多级容器的内存地址还是相同的。
import copy
a = [[66,88], 2, 3]
b = copy.copy(a)
print(a, id(a)) # [[66, 88], 2, 3] 2431683163720
print(b, id(b)) # [[66, 88], 2, 3] 2431683162184
# 改变二级容器
a[0].append(100)
print(a, id(a)) # [[66, 88, 100], 2, 3] 2431683163720
print(b, id(b)) # [[66, 88, 100], 2, 3] 2431683162184
# 浅拷贝不能拷贝二级及以上的容器
print(id(a[0])) # 1582481372872
print(id(b[0])) # 1582481372872
深拷贝
浅拷贝只能拷贝一级容器
所以诞生了深拷贝,深拷贝可以拷贝所有级别的容器。
import copy
a = [[66,88], 2, 3]
# 深拷贝使用deepcopy函数
b = copy.deepcopy(a)
print(a, id(a)) # [[66, 88], 2, 3] 2168411158088
print(b, id(b)) # [[66, 88], 2, 3] 2168411156552
a[0].append(100)
print(a, id(a)) # [[66, 88, 100], 2, 3] 2168411158088
print(b, id(b)) # [[66, 88], 2, 3] 2168411156552
# 深拷贝所有级别的容器
print(id(a[0])) # 2168411158216
print(id(b[0])) # 2168411122760
来源:https://blog.51cto.com/u_14926812/5098241


猜你喜欢
- 前言这里先说明一下,网上很多人说阿里规定500w数据就要分库分表。实际上,这个500w并不是定义死的,而是与MySQL的配置以及机器的硬件有
- 前言由于pycharm自带的pip源网站是国外网址,这就导致了许多国内用户在pycharm中下载其他软件包速度极慢,有时还会跳出下载失败的界
- 本文详细罗列并说明了Python的标准库与第三方库如下,供对此有需要的朋友进行参考:Tkinter———— Python默认的图形界面接口。
- while语句打印1-20的整数,并且每行打印五个数,为了实现每行5个数,我们使用一个if判断语句来实现,判断当打印出5个数之后,自动换行打
- QSlider 是一个具有可来回拉动手柄的控件。有时使用滑块比输入数字或使用旋转框更方便。在我们的例子中,我们将创建一个滑块和一个标签。标签
- mysql数据库自不必说,现在很多程序开发应用及站长们常用到,jdbc可能一般会比较陌生一些,jdbc是什么意思?这里也会提到,最主要的是为
- Pandas查询数据的几种方法df.loc方法,根据行、列的标签值查询df.iloc方法,根据行、列的数字位置查询df.where方法df.
- 传统的网页BBS大多是采用CGI模式实现的,它的实现要求编程者既要掌握编程语言如Perl或C等,又要了解关于CGI模式的各项技术内容,因此要
- 一、先进行剪切操作圆形区域占图片可能不多,多余的部分不要。看下图。只要纽扣电池内部和少许的边缘部分,其余黑色背景部分不需要。先沿着纽扣电池的
- 1. 卡住是怎么办按照以下步骤, 前提是你需要懂点英文:尽可能自己想办法解决仔细阅读相关文档, 确保不错过任何相关内容在Google, 百度
- 1. 简介在一些研究领域很多经典算法和工具都由上古语言Fortran编写,而这部分代码又没有对应的C/C++和Python版本。因此,掌握P
- 教你用Python批量查询关键词微信指数。前期准备安装好Python开发环境及Fiddler抓包工具。前期准备安装好Python开发环境及F
- 1下载安装1.1打开官网http://www.jetbrains.com/pycharm/download/#section=windows
- PID算法实现import timeclass PID: def __init__(self, P=0.2, I=0.0, D=
- 一、绪论在使用python开发过程中经常会使用到第三方库。因此就涉及到了如何安装、复制移动。二、安装方式第三方库的安装方式1、python自
- 1.按姓氏笔画排序:Select * From TableName Order By CustomerName Collate Chines
- 在接口测试学习过程中,遇到了利用requests库进行文件下载和上传的问题。同样,在真正的测试过程中,我们不可避免的会遇到上传和下载的测试。
- 项目地址https://github.com/jonssonyan...开发工具 python 3.7.9pycharm 2019.3.5
- 我想没多少人敢保证写JavaScript能不用调试,那选择用什么方式调试会比较好呢?告别了我最爱的alert("MM")
- 本文实例讲述了Python使用文件锁实现进程间同步功能。分享给大家供大家参考,具体如下:简介在实际应用中,会出现这种应用场景:希望shell