当前位置: 首页 > 编程日记 > 正文

Python_赋值和深浅copy

Python中赋值和深浅copy存储变化    

在刚学python的过程中,新手会对python中赋值、深浅copy的结果感到丈二和尚。经过多次在网上查找这几个过程的解释说明以及实现操作观察,初步对这几个过程有了浅显的认识。以下内容仅是我在学习过程中遇到的问题,然后上网搜验证,最后理解。博文也许没有将这部分内容写明白,也许有不对的地方,如果有大佬看到希望能指点一下新人。随着后面的学习以及理解会再次补充此内容。

  • id函数

  id方法的返回值就是对象的内存地址

  • 执行赋值语句

  在python中执行一条赋值语句,python解释器做了这两件事情:

  1.在内存中创建一个字符串;

  2.在内存中创建一个变量,并把字符串的内存地址赋值给变量;

1 >>> a='haizei'
2 >>> id(a)
3 1895098520440    #字符串‘haizei’的内存地址

  python解释器在内存中创建一个字符串‘haizei’,创建一个指针a,并把字符串的内存地址保存在指针中。指针就指向了字符串,访问指针a就是访问字符串‘haizei’。

  • 赋值a赋值给变量b

1 >>> a='haizei'
2 >>> id(a)
3 1895098520440
4 >>> b=a
5 >>> id(b)
6 1895098520440    #a和b的指向的值的内存地址是相同的,说明赋值是把变量a指向的值的内存地址赋值给b,使b和a一样也指向同一个内存地址。b和a都是存储的值的内存地址

  执行b=a,创建了一个变量b,并把b指向a指向的字符串的内存地址。

  执行b=a,创建一个指针b,并把存储在指针a中的内存地址赋值给指针b,这样指针b就也指向了a指向的字符串。赋值完成后b就和a没有任何关系了,只和它指向的字符串有关系。

  • 重新给a赋值
 1 >>> a='haizei'
 2 >>> id(a)
 3 1895098520440
 4 >>> b=a
 5 >>> id(b)
 6 1895098520440
 7 >>> a='lufei'   #python解释器在内存中新开辟一块空间创建字符串‘lufei’,并把a重新指向字符串‘abc’
 8 >>> id(a)
 9 1895098520496
10 >>> id(b)
11 1895098520440   #变量b指向的还是原来的字符串

前面给变量a赋值,把a的值赋给b,结果是在内存中创建了一个值,a和b都指向了这个值。现在重新给a赋一个新的值,执行一条赋值语句,过程是在内存中创建一个新的值,然后把新值的内存地址保存在变量指针a中。结果是内存中存在两个值b指向原来的值,a指向新创建的值。以上结果说明对于赋值操作,如果是将另一个变量的值赋给一个变量实际上是将另一个变量存储的值的内存地址同样保存在被赋予值的变量中;如果是给变量赋一个新的值,那么相当于是一个初始化操作会在内存中开辟一段空间创建一个值,将值的内存地址保存在被赋值的变量指针中。

  • 创建复杂数据结构
1 >>> name=['lufei','suolong','namei']
2 >>> id(name)
3 1895098506504
4 >>> id(name[0])
5 1895098520496
6 >>> id(name[1])
7 1895098520608
8 >>> id(name[2])
9 1895098520664

  创建的列表的名称为name,从代码结果可以看到:列表name指向的整体内存地址和列表中每个元素指向的地址都不相同。说明对于复杂的数据结构来说,里面存储的也只是一个个值的内存地址。从下图可以看出来对于元组、列表、字典这样的复杂的数据结构,在内存中其变量和值是分开的,每个元素都对应一个变量指针,变量指针指向值的位置。变量和值的存储是分开的,把整个数据结构赋值给另一个变量的执行过程是在内存中创建相同数量的一些变量,然后把原数据结构中存储在变量中的值的地址赋值给新创建的变量。结果如右图。

  

对列表中的元素的增删改查操作不会影响到列表本身的内存地址,改变的是列表内的某个元素的地址引用;如果是重新初始化一个列表那么修改的是列表名称指向的整个列表的内存地址。可当我们给name这个列表重新初始化赋值时,就给name这个变量重新赋予了一个新的内存地址,覆盖了原来的列表的地址。

 1 >>> name=['lufei','suolong','namei']
 2 >>> id(name)
 3 1895098506504
 4 >>> id(name[0])
 5 1895098520496
 6 >>> id(name[1])
 7 1895098520608
 8 >>> id(name[2])
 9 1895098520664
10 >>> name[0]='zhang'    #重新给序号为0的元素赋值
11 >>> id(name)           #整个列表的内存地址没有改变
12 1895098506504
13 >>> id(name[0])
14 1895098520552          #序号为0的元素的内存地址发生改变
15 >>> name=['zhao','qian','sun']        #重新初始化赋值name这个变量
16 >>> id(name)
17 1895098512136                         #name这个变量指向的内存地址发生了改变

这里重新给name变量赋值,赋一个新的列表给name。整个过程以及结果和上面的单个变量的赋值是类似的,不同的是这里是一个列表是多个单个元素(变量)的集合。相当于是对多个变量做这样的操作。

  • 浅copy
 1 >>> name={'lufei':'cap','haizei':['suolong','namei','qiaoba']}   #1、创建字典name
 2 >>> a=name.copy()           #执行copy方法,吧结果赋值给字典a
 3 >>> id(name)
 4 1895098004488
 5 >>> id(a)
 6 1895098007368               #从内存地址上看原来的name的内存地址和a的内存地址不相同,说明copy是创建了一个name的副本,把副本的内存地址保存在变量a中
 7 >>> id(name['lufei'])
 8 1895098521056
 9 >>> id(a['lufei'])
10 1895098521056               #分别查看原字典name和副本字典a中键‘lufei’的值的内存地址,地址相同。说明这里存储的是同一个值
11 >>> id(name['haizei'])
12 1895098506504
13 >>> id(a['haizei'])
14 1895098506504               #同样副本中另一个键的值的内存地址也是相同的,说明两个字典内的键都指向相同的值
15 >>> name['lufei']='haha'    #执行赋值语句修改name字典中键‘lufei’的值
16 >>> name['haizei'].remove('namei')       #调用字典name中‘haizei’键的值,并调用值的remove方法移除列表中的‘namei’元素
17 >>> name
18 {'haizei': ['suolong', 'qiaoba'], 'lufei': 'haha'}
19 >>> a
20 {'haizei': ['suolong', 'qiaoba'], 'lufei': 'cap'}     #分别查看字典name和a,发现对字典name执行赋值语句时,副本没有跟着修改,对键‘haizei’做的修改副本跟着做了修改?
21 >>> id(name)
22 1895098004488
23 >>> id(a)
24 1895098007368        #分别查看两个字典的内存地址,和修改之前的内存地址是一样的。说明修改复杂的数据结构中元素的值不影响变量对整体数据结构内存地址的指向(数据结构的内存地址没有改变)
25 >>> id(name['lufei'])
26 1895098520944
27 >>> id(a['lufei'])
28 1895098521056        #分别查看两个字典中键‘lufei’的值的内存地址,发现name中该键的值被修改了其内存地址改变了。而字典a的键的值没有改变,对应的该键的值的内存地址没有改变。
29 >>> id(name['haizei'])
30 1895098506504
31 >>> id(a['haizei'])
32 1895098506504        #对字典name中键‘haizei’的值做了修改,但是查看该键的值的内存地址时,两个字典都没有变化,和修改前是一样的?

在理解深浅copy的时候,先用一张图来表示字典在内存中的存在方式,再说明深浅copy分别copy的是字典的那些部分。当对原字典或者副本进行修改时,修改的部分在 内存中造成什么变化,是否对原字典和副本字典产生了影响。当理解了这些的时候也就理解了深浅copy

这是我们在内存中创建的字典的存在形式。可以这么理解,字典name保存整体字典的内存地址从而指向这个字典,字典内包含两个键,键1保存的是一个值的内存地址从而指向这个值,键2保存的是一个列表的整体地址从而指向这个列表。列表内又有三个指针分别保存三个值的内存地址作为列表的三个元素。

浅copy复制的是哪部分?浅copy仅复制了图中的字典变量的部分。也就是复制了键1下保存的内存地址和键而的内存地址

当修原字典或者副本字典的键1关联的值时,在内存中开辟一片新的空间存储一个新的值,并把新创建的值的内存地址保存到被修改的字典的对应键的指针里。因此被修改的字典的键指向了新创建的值,未被修改的字典中相同的键指向的还是原来的值,所以当修改的键对应的值是一个简单的数据类型的值时,修改后原字典和副本字典的值出现了不同。

当修改的键对应的值是一个数据结构时,由于原字典中键2中仅保存了列表的整体地址,副本字典中copy的时候,键2也仅仅是copy的整个列表的内存地址。原字典和副本字典都不清楚列表中值的内存地址是多少,只是通过列表的整体地址可以访问到列表中的值。在这种情况下列表中的值发生变化时就对原字典和副本字典都产生了影响。

  • 深copy
 1 >>> from copy import deepcopy         #使用深copy时需要从copy模块中导入deepcopy
 2 >>> name={'captain':'lufei','sailor':['suolong','namei','qiaoba']}
 3 >>> copy_name=deepcopy(name)          #执行深copy
 4 >>> id(name)
 5 1595431826440
 6 >>> id(copy_name)
 7 1595435745864                         #查看原字典和副本字典的内存地址,地址不同
 8 >>> id(name['sailor'])
 9 1595437385096
10 >>> id(copy_name['sailor'])
11 1595437383816                         #查看原字典和副本字典列表值对应的键下存储的内存地址,地址不同。说明当键对应的值是一个复杂的数据结构时deepcopy会继续复制到下一层。在浅copy中原字典和副本字典的这
12 >>> id(name['sailor'][1])             #里是相同的。
13 1595435816248
14 >>> id(copy_name['sailor'][1])
15 1595435816248                         #当查看原字典和副本字典中列表值下的元素的地址时发现,其内存地址又是相同的。

由上面的内存地址的查看可以绘制出深copy时copy的范围对应的图

可以对比浅copy时的结果的图中不一样的地方来理解。

高级语言中,变量是对内存及其地址的抽象。在python中变量的内存地址和变量值的内存地址是分开的--python中内存的变量存储情况。

每个变量中都存储了这个变量的地址,而不是值本身;对于复杂的数据结构来说,里面存储的也只是每个元素的内存地址而已,并不是值本身;

在python中执行一条赋值语句如a='abc'python解释器做了两件事情:

1.在内存中创建了一个字符串‘abc’

2.在内存中创建了一个名为a的变量,并把它指向‘abc’

变量的每次初始化,都开辟了一个新的空间,并把新内容的内存地址赋值给变量

  

转载于:https://www.cnblogs.com/freeasyman/p/8759664.html

相关文章:

萌新养成 | AI科技大本营实习生招募计划

金三银四跳槽季这个时候需要做好准备的可不仅仅只有在职或者离职的萝卜尚未毕业的萌新也需要提早做准备了毕竟把自己修炼成一个优秀的萝卜也不是一件容易的事所以,放下你找对象、刷副本、世界游的想法加入我们为你量身定制的人才培养计划加入营长的团队,…

踏上云旅程 存储准备好了吗

在云计算的概念刚出现时,人们习惯将原始数据存在本地,而将备份数据放到云中。随着云计算技术和应用逐渐走向成熟,人们可能会把原始数据存在云中,而把备份数据放在本地。全球存储网络工业协会(SNIA)主席Wayn…

UCloud与NTT达成合作,提供可靠跨地域混合云服务

近日,UCloud宣布与NTT Communications东亚地区总部NTT Com Asia (以下简称“NTT Com Asia”) 达成合作伙伴协议。双方将发挥各自优势,通过UCloud云服务与NTT Communications企业级 Enterprise Cloud 服务互联互通,为国内企业以及进入中国的跨…

ICCV 2019论文投稿数破纪录,中科院、清华名列前茅,苹果垫底

参加 2019 Python开发者日,请扫码咨询 ↑↑↑整理 | 琥珀出品 | AI科技大本营(ID:rgznai100)昨日,作为计算机视觉领域里顶级会议这一的 International Conference on Computer Vision (ICCV)公布了 2019 年…

【linux】在CentOS7上更改端口号时报错:Job for sshd.service failed because the control process exited with error

1、问题描述 在在CentOS7上更改端口号时报错: Job for sshd.service failed because the control process exited with error code.See “systemctl status sshd.service” and “journalctl -xe” for details. 2、修改ssh端口号的方法 修改:$ sudo …

硅谷风投押注计算机网络安全市场

今天,新浪转载了一篇外媒报道,称随着一系列安全事件的集中爆发,风险投资家们业从计算机安全领域看到了机会,希望加大对这一市场的投资。 文章最后指未来几年可能上市的公司包括:梭子鱼、Proofpoint、Palo Alto Network…

Tensorflow框架是如何支持分布式训练的?

参加 2019 Python开发者日,请扫码咨询 ↑↑↑作者 | 杨旭东转载自知乎《算法工程师的自我修养》专栏Methods that scale with computation are the future of AI. —Rich Sutton, 强化学习之父大数据时代的互联网应用产生了大量的数据,这些数据就好比是石…

【linux】SELinux工具:semanage的安装和使用

1、安装 在ubuntu14.04上安装 sudo apt-get install policycoreutils在CentOS7上安装 sudo yum -y install policycoreutils-python2、semanage命令行参数 $ semanage --help semanage用于配置SELinux策略的某些元素,而不需要对策略源进行修改或重新编译。 位置…

在阿里云Kubernetes容器服务上打造TensorFlow实验室

简介 Jupyter notebook是强大的数据分析工具,它能够帮助快速开发并且实现机器学习代码的共享,是数据科学团队用来做数据实验和组内合作的利器,也是机器学习初学者入门这一个领域的好起点。 而TensorFLow是深度学习和机器学习最流行的开源框架…

PagedGeometry 笔记03

1. 创建草 PagedGeometry *grass new PagedGeometry(mCamera,50); grass->addDetailLevel<GrassPage>(100); // 在100单位内绘草。 GrassLoader *grassLoader new GrassLoader(grass); grass->setPageLoader(grassLoader); grassLoader->setH…

【Qt中文手册】QSortFilterProxyModel

1、说明 QSortFilterProxyModel类继承自QAbstractProxyModel是一个代理类,存在于另一模型Model和视图View之间,将另一个模型排序或者过滤后在视图上显示。 2、简单示例 没有使用代理的项视图模型代码如下 QTreeView *treeView = new QTreeView; MyItemModel *model = new…

吴恩达的Landing.ai又迎来一位AI大牛

参加 2019 Python开发者日&#xff0c;请扫码咨询 ↑↑↑整理 | 琥珀出品 | AI科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09;近日&#xff0c;吴恩达在Twitter发消息称&#xff0c;欢迎王冬岩加入Landing.ai&#xff0c;负责公司的客户对接及战略伙伴合作&#x…

synchronize

1。synchronize方法的产生与vcl的局限性有关,因为vcl控件在同一时刻只能被单线程访问&#xff0c;如果多个线程同时访问vcl,vcl会出现问题。所以问了安全地访问vcl,Tthread类提供了一个方法叫synchronize&#xff0c;他可以让线程中的方法在主线程中执行&#xff0c;所以我们可…

Google BBR拥塞控制算法背后的数学解释 | 深度

参加 2019 Python开发者日&#xff0c;请扫码咨询 ↑↑↑作者 | 赵亚转载自CSDN网站杭州待了一段时间&#xff0c;回到深圳过国庆假期&#xff0c;无奈温州皮鞋?厂老板过节要回温州和上海&#xff0c;不在深圳&#xff0c;也就没有见着&#xff0c;非常遗憾&#xff01;国庆节…

【Linux】linux使用mplayer播放摄像头

1、安装mplayer 1.1 在ubuntu上安装mplayer sudo apt-get install mplayer1.2 在Centos7上安装mplayer 安装软件包&#xff1a; sudo yum localinstall http://download1.rpmfusion.org/free/el/rpmfusion-free-release-7.noarch.rpm安装mplayer&#xff1a; sudo yum ins…

leetCode刷题 2. 两数相加

原题链接&#xff1a; leetcode-cn.com/problems/ad… 题目描述 给定两个非空链表来表示两个非负整数。位数按照逆序方式存储&#xff0c;它们的每个节点只存储单个数字。将两数相加返回一个新的链表。 你可以假设除了数字 0 之外&#xff0c;这两个数字都不会以零开头。 示例&…

【Qt】pro 笔记

一、小技巧 1、获取pro文件所在目录的最后一级目录名 LASTDIR = $$relative_path($$_PRO_FILE_PWD_, $$_PRO_FILE_PWD_/..)2、获取变量的值 $$VAR:获取变量值; $${VAR}:获取变量值,{}的存在可以和后面的字符做隔离; $$(VAR):在执行qmake时,获取环境变量的值; $(VAR)…

7——ThinkPhp中的响应和重定向:

public function index3(){//响应数据&#xff1a;$data[title>"标题部分","content">"内容部分"];//return json($data);//return json($data,201);//return xml($data);//请求信息给模板&#xff1a;$this->assign(name,xiaoming222)…

GitHub超全机器学习工程师成长路线图,开源两日收获3700+Star!

参加 2019 Python开发者日&#xff0c;请扫码咨询 ↑↑↑ 大会议题以及更多详情请查看&#xff1a;https://pythondevdays2019.csdn.net/ 作者 | 琥珀 出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09; 近日&#xff0c;一个在 GitHub 上开源即收获了 3700 Star 的项…

Android模拟器SD卡的使用

在Eclipse中&#xff0c;操作如下&#xff1a; 在设置了RUN的命令参数之后&#xff0c;RUN一个应用&#xff0c;然后使用DDMS的File Explorer工具导入导出文件。 打开DDMS工具&#xff1a;在Eclipse的Window->Open Perspective->Other...里面打开DDMS工具。 在DDMS的File…

受用一生的高效PyCharm使用技巧

参加 2019 Python开发者日&#xff0c;请扫码咨询 ↑↑↑作者 | Python编程时光转载自Python编程时光&#xff08;ID:Python-Time&#xff09;今天先从 PyCharm 入手&#xff0c;写一些可以明显改善开发效率的使用技巧&#xff0c;一旦学会&#xff0c;受用一生。以下代码演示是…

【Go】Go基础(一):Hello World!

1、 C格式hello.go package main import "fmt"func main(){fmt.Printf("Hello World!\n"); }2、编译 go build hello.go3、运行 执行go build编译后&#xff0c;会在当前目录下生成名为hello的可执行程序。 $ ./hello Hello World!4、Go格式的hello.g…

centos7上搭建http服务器以及设置目录访问

参考文献&#xff1a;http://www.jb51.net/article/137596.htm&#xff0c;原文摘抄如下&#xff0c;并根据具体需要作了相应的修改。 步骤&#xff1a; 1. 安装httpd服务 sudo yum install httpd Apache 的所有配置文件都位于 /etc/httpd/conf 和 /etc/httpd/conf.d 。网站…

一文看懂深度学习发展史和常见26个模型

参加 2019 Python开发者日&#xff0c;请扫码咨询 ↑↑↑来源 | AI部落联盟&#xff08;ID&#xff1a;AI_Tribe&#xff09;作者简介&#xff1a;沧笙踏歌&#xff0c;硕士毕业于北京大学&#xff0c;目前计算机科学与技术博士在读&#xff0c;主要研究自然语言处理和对话系统…

JBL无所不能与IPhone4、IPad2的完美盛宴

期待以久JBL白版终于到货了&#xff0c;由于水货的供电参数是110V~200V&#xff0c;行货是110~220V&#xff0c;所以本人选择了行货&#xff0c;因为水货的供电和国内的输入电压不符&#xff0c;时间用久了会影响小J寿命。经过测试后本人发现&#xff0c;用JBL无所不能连接IPho…

【Go】Go基础(二):学习网址汇总

Go语言中文网站 https://studygolang.com/ Go语言标准库文档 https://studygolang.com/pkgdoc 《The Way to Go》中文名《Go 入门指南》 https://github.com/Unknwon/the-way-to-go_ZH_CN https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/directory.md…

堆和栈的主要区别由以下几点:

1、管理方式不同&#xff1b;2、空间大小不同&#xff1b;3、能否产生碎片不同&#xff1b;4、生长方向不同&#xff1b;5、分配方式不同&#xff1b;6、分配效率不同&#xff1b;管理方式&#xff1a;对于栈来讲&#xff0c;是由编译器自动管理&#xff0c;无需我们手工控制&a…

参与2011年7月13日举行的Azure国际猜拳锦标赛,赢取5,000美元大奖

你想要编写自己的“bot”角色并测试你的技能&#xff0c;在线同来自美国&#xff0c;加拿大&#xff0c;中国&#xff0c;德国&#xff0c;新西兰&#xff0c;瑞典和英国的Windows Azure开发者一教高下&#xff0c;并赢取5,000美元大奖吗&#xff1f;请先注册Azure国际猜拳锦标…

【Go】Go基础(三):基本结构和基本数据类型

1、Go程序源码结构 我们将一个Go程序的源码暂时称为一个项目 &#xff1a; 每个项目由若干个包组成&#xff1b; 每个包由同一个目录中的若干个go文件组成&#xff1b; 每个go文件中由若干函数、变量、常量等组成&#xff1b; 每个函数由流程控制语句、变量、常量、运算符和函…

2019如何学Python?这里有你需要的答案

点击上方↑↑↑蓝字关注我们~参加 2019 Python开发者日&#xff0c;请扫码咨询 ↑↑↑编辑 | Jane出品 | Python大本营&#xff08;公众号id&#xff1a;pythonnews&#xff09;根据 2018 年 Python 开发者大调查&#xff0c;Python 3 的渗透率已经快速增长至 84%&#xff0c;越…