python变量的存储原理详解


Posted in Python onJuly 10, 2019

变量的存储

在高级语言中,变量是对内存及其地址的抽象。

对于python而言,python的一切变量都是对象,变量的存储,采用了引用语义的方式,存储的只是一个变量的值所在的内存地址,而不是这个变量的只本身。

引用语义:在python中,变量保存的是对象(值)的引用,我们称为引用语义。采用这种方式,变量所需的存储空间大小一致,因为变量只是保存了一个引用。也被称为对象语义和指针语义。

值语义:有些语言采用的不是这种方式,它们把变量的值直接保存在变量的存储区里,这种方式被我们称为值语义,例如C语言,采用这种存储方式,每一个变量在内存中所占的空间就要根据变量实际的大小而定,无法固定下来。

由于python中的变量都是采用的引用语义,数据结构可以包含基础数据类型,导致了在python中每个变量中都存储了这个变量的地址,而不是值本身;

对于复杂的数据结构来说,里面的存储的也只只是每个元素的地址而已,下面给出基础类型和数据结构类型变量重新赋值的存储变化:

1.数据类型重新初始化对python语义引用的影响

变量的每一次初始化,都开辟了一个新的空间,将新内容的地址赋值给变量。对于下图来说,我们重复的给str1赋值,其实在内存中的变化如下右图:

python变量的存储原理详解

python变量的存储原理详解

从上图我们可以看出,str1在重复的初始化过程中,是因为str1中存储的元素地址由'hello world'的地址变成了'new hello world'的。

2.数据结构内部元素变化重对python语义引用的影响

对于复杂的数据类型来说,改变其内部的值对于变量的影响:

python变量的存储原理详解

python变量的存储原理详解

当对列表中的元素进行一些增删改的操作的时候,是不会影响到lst1列表本身对于整个列表地址的,只会改变其内部元素的地址引用。可是当我们对于一个列表重新初始化(赋值)的时候,就给lst1这个变量重新赋予了一个地址,覆盖了原本列表的地址,这个时候,lst1列表的内存id就发生了改变。上面这个道理用在所有复杂的数据类型中都是一样的。

变量赋值

1.str的赋值

python变量的存储原理详解

python变量的存储原理详解

我们刚刚已经知道,str1的再次初始化(赋值)会导致内存地址的改变,从上图的结果我们可以看出修改了str1之后,被赋值的str2从内存地址到值都没有受到影响。

看内存中的变化,起始的赋值操作让str1和str2变量都存储了‘hello world'所在的地址,重新对str1初始化,使str1中存储的地址发生了改变,指向了新建的值,此时str2变量存储的内存地址并未改变,所以不受影响。

2.复杂的数据结构中的赋值

刚刚我们看了简单数据类型的赋值,现在来看复杂数据结构变化对应内存的影响。

python变量的存储原理详解

python变量的存储原理详解

上图对列表的增加修改操作,没有改变列表的内存地址,lst1和lst2都发生了变化。

对照内存图我们不难看出,在列表中添加新值时,列表中又多存储了一个新元素的地址,而列表本身的地址没有变化,所以lst1和lst2的id均没有改变并且都被添加了一个新的元素。

简单的比喻一下,我们出去吃饭,lst1和lst2就像是同桌吃饭的两个人,两个人公用一张桌子,只要桌子不变,桌子上的菜发生了变化两个人是共同感受的。

浅拷贝

首先,我们来了解一下浅拷贝。浅拷贝:不管多么复杂的数据结构,浅拷贝都只会copy一层。下面就让我们看一张图,来了解一下浅浅拷贝的概念。

python变量的存储原理详解

python变量的存储原理详解

看上面两张图,我们加入左图表示的是一个列表

sourcelist,sourcelist = ['str1','str2','str3','str4','str5',['str1','str2','str3','str4','str5']];

右图在原有的基础上多出了一个浅拷贝的copylist,

copylist = ['str1','str2','str3','str4','str5',['str1','str2','str3','str4','str5']];

sourcelist和copylist表面上看起来一模一样,但是实际上在内存中已经生成了一个新列表,copy了sourceLst,获得了一个新列表,存储了5个字符串和一个列表所在内存的地址。

我们看下面分别对两个列表进行的操作,红色的框框里面是变量初始化,初始化了上面的两个列表;我们可以分别对这两个列表进行操作,例如插入一个值,我们会发现什么呢?如下所示:

python变量的存储原理详解

从上面的代码我们可以看出,对于sourceLst和copyLst列表添加一个元素,这两个列表好像是独立的一样都分别发生了变化,但是当我修改lst的时候,这两个列表都发生了变化,这是为什么呢?我们就来看一张内存中的变化图:

python变量的存储原理详解

我们可以知道sourceLst和copyLst列表中都存储了一坨地址,当我们修改了sourceLst1的元素时,相当于用'sourceChange'的地址替换了原来'str1'的地址,所以sourceLst的第一个元素发生了变化。而copyLst还是存储了str1的地址,所以copyLst不会发生改变。

当sourceLst列表发生变化,copyLst中存储的lst内存地址没有改变,所以当lst发生改变的时候,sourceLst和copyLst两个列表就都发生了改变。

这种情况发生在字典套字典、列表套字典、字典套列表,列表套列表,以及各种复杂数据结构的嵌套中,所以当我们的数据类型很复杂的时候,用copy去进行浅拷贝就要非常小心。。。

深拷贝

深拷贝——即python的copy模块提供的另一个deepcopy方法。深拷贝会完全复制原变量相关的所有数据,在内存中生成一套完全一样的内容,在这个过程中我们对这两个变量中的一个进行任意修改都不会影响其他变量。下面我们就来试验一下。

python变量的存储原理详解

看上面的执行结果,这一次我们不管是对直接对列表进行操作还是对列表内嵌套的其他数据结构操作,都不会产生拷贝的列表受影响的情况。我们再来看看这些变量在内存中的状况:

python变量的存储原理详解

看了上面的内容,我们就知道了深拷贝的原理。其实深拷贝就是在内存中重新开辟一块空间,不管数据结构多么复杂,只要遇到可能发生改变的数据类型,就重新开辟一块内存空间把内容复制下来,直到最后一层,不再有复杂的数据类型,就保持其原引用。这样,不管数据结构多么的复杂,数据之间的修改都不会相互影响。这就是深拷贝~~~

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python 装饰器功能以及函数参数使用介绍
Jan 27 Python
Python使用scrapy抓取网站sitemap信息的方法
Apr 08 Python
linux平台使用Python制作BT种子并获取BT种子信息的方法
Jan 20 Python
python中的字典操作及字典函数
Jan 03 Python
Python下调用Linux的Shell命令的方法
Jun 12 Python
python 3.7.0 下pillow安装方法
Aug 27 Python
Python编写合并字典并实现敏感目录的小脚本
Feb 26 Python
python实现统计文本中单词出现的频率详解
May 20 Python
python实现socket+threading处理多连接的方法
Jul 23 Python
Python将列表中的元素转化为数字并排序的示例
Dec 25 Python
Python中的sys.stdout.write实现打印刷新功能
Feb 21 Python
Python socket连接中的粘包、精确传输问题实例分析
Mar 24 Python
python中 * 的用法详解
Jul 10 #Python
通过python实现随机交换礼物程序详解
Jul 10 #Python
Python实现简单的列表冒泡排序和反转列表操作示例
Jul 10 #Python
Python获取好友地区分布及好友性别分布情况代码详解
Jul 10 #Python
Python中的类与类型示例详解
Jul 10 #Python
使用python打印十行杨辉三角过程详解
Jul 10 #Python
python简单实现矩阵的乘,加,转置和逆运算示例
Jul 10 #Python
You might like
PHP怎样调用MSSQL的存储过程
2006/10/09 PHP
(PHP实现)只使用++运算实现加法,减法,乘法,除法
2013/06/27 PHP
教你如何在CI框架中使用 .htaccess 隐藏url中index.php
2014/06/09 PHP
更优雅的事件触发兼容
2011/10/24 Javascript
ASP.NET jQuery 实例8 (动态添加内容到DropDownList)
2012/02/03 Javascript
javascript实现TreeView 无刷新展开的实例代码
2013/07/13 Javascript
jQuery中对未来的元素绑定事件用bind、live or on
2014/04/17 Javascript
JavaScript模拟实现继承的方法
2015/03/30 Javascript
轻松学习jQuery插件EasyUI EasyUI创建RSS Feed阅读器
2015/11/30 Javascript
JS实现设置ff与ie元素绝对位置的方法
2016/03/08 Javascript
require.js+vue开发微信上传图片组件
2016/10/27 Javascript
详解vue项目优化之按需加载组件-使用webpack require.ensure
2017/06/13 Javascript
AngularJS ui-router刷新子页面路由的方法
2018/07/23 Javascript
js实现web调用摄像头 js截取视频画面
2019/04/21 Javascript
node实现简单的增删改查接口实例代码
2019/08/22 Javascript
[19:15]DK战队纪录片
2014/09/02 DOTA
[01:09]DOTA2次级职业联赛 - ishow.HMM战队宣传片
2014/12/01 DOTA
Python中捕捉详细异常信息的代码示例
2014/09/18 Python
python超简单解决约瑟夫环问题
2015/05/12 Python
Windows上配置Emacs来开发Python及用Python扩展Emacs
2015/11/20 Python
Scrapy爬虫实例讲解_校花网
2017/10/23 Python
利用python爬取斗鱼app中照片方法实例
2017/12/03 Python
Django+Ajax+jQuery实现网页动态更新的实例
2018/05/28 Python
由面试题加深对Django的认识理解
2019/07/19 Python
aws 通过boto3 python脚本打pach的实现方法
2020/05/10 Python
python矩阵运算,转置,逆运算,共轭矩阵实例
2020/05/11 Python
Python如何实现后端自定义认证并实现多条件登陆
2020/06/22 Python
Python实现打包成库供别的模块调用
2020/07/13 Python
基于opencv实现简单画板功能
2020/08/02 Python
matplotlib部件之矩形选区(RectangleSelector)的实现
2021/02/01 Python
Html5实现移动端、PC端 刮刮卡效果
2016/06/30 HTML / CSS
斯洛伐克时尚服装网上商店:Cellbes
2016/10/20 全球购物
惊艳的手工时装首饰:Migonne Gavigan
2018/02/23 全球购物
有影响力的人、名人和艺术家的官方商品:Represent
2019/11/26 全球购物
计划生育汇报材料
2014/12/26 职场文书
2015年餐厅服务员工作总结
2015/04/23 职场文书