一、Python的变量及其存储

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

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

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

  

二、各基本上数据结构的地址存储及改变情况

  在python中的数据类型包括:bool、int、long、float、str、set、list、tuple、dict等等。这些数据类型可以分为简单数据类型和复杂数据类型。

  简单数据类型和复杂数据类型的划分依据:如果一个数据类型,可以将其它的数据类型作为自己的元素,则可以认为这是一种数据结构。数据结构的分类有很多种,在Python中常用的只有集合、序列和映射三种结构。对应python中的set、list(tuple、str)、dict。常用的数据类型有int、long、float、bool、str等类型。

  

  由于python中的变量都是采用的引用语义,数据结构可以包含基础数据类型,导致了在python中的数据存储方式存在下图所示的这种情况,每个变量中都存储了这个变量的地址,而不是值本身;对于复杂的数据结构来说。里面的存储也只是每个元素的地址而已。

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

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

>>> test = 'hello world'
>>> id(test)
4363600816
>>> test = 'a new string'
>>> id(test)
4363600880

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

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

>>> lst1 = [1,2,3,4,5]
>>> id(lst1)
4363600328
>>> lst1.append('new item')
>>> id(lst1)
4363600328
>>> lst1[0] = 'test item'
>>> id(lst1)
4363600328
>>> lst1 = [1,2,3,4]
>>> id(lst1)
4363600264

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

三、变量的赋值

  1. 简单数据类型的赋值

>>> str1 = 'hello world'
>>> str2 = str1
>>> id(str1)
4363601072
>>> id(str2)
4363601072
>>> str1 = 'nihao'
>>> id(str1)
4363608112
>>> id(str2)
4363601072

    

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

  2. 复杂数据结构中赋值

>>> lst1 = [1,2,3,4]
>>> lst2 = lst1
>>> id(lst1)
4363600328
>>> id(lst2)
4363600328
>>> lst1[0] = 'test'
>>> lst1
['test', 2, 3, 4]
>>> lst2
['test', 2, 3, 4]

  上述代码增加修改操作,但是并没有对lst2做出改变,结果lst1和lst2都发生了变化。

四、拷贝简述

  上述内容讲述了变量赋值的过程。对于复杂的数据结构来说,赋值就等于完全共享了资源,一个值的改变会完全被另一个值共享。

  然而有时候,我们偏偏需要将一份数据的原始内容保留一份,再去处理数据,这个时候使用赋值就不够明智了。python为这种需求提供了copy模块。提供了两种主要的copy方法,一种是普通的copy,另一种是deepcopy。我们称前者为浅拷贝,后者为深拷贝。

五、浅拷贝

  浅拷贝:不管多么复杂的数据结构、浅拷贝都只会copy一层。

  

import copy

lst = ['str1', 'str2', 'str3', 'str4', 'str5']
sourceLst = ['str1', 'str2', 'str3', 'str4', 'str5', lst]
copyLst = copy.copy(sourceLst) print('1.->sourceLst:', sourceLst)
print('1.->copyLst:', copyLst) sourceLst.append('sourcestr')
copyLst.append('copystr') print('2.->sourceLst:', sourceLst)
print('2.->copyLst:', copyLst) sourceLst[0] = 'changestr'
print('3.->sourceLst:', sourceLst)
print('3.->copyLst:', copyLst) lst.append('testAppend')
print('4.->sourceLst:', sourceLst)
print('4.->copyLst:', copyLst)

  上述代码执行会是下述结果:

1.->sourceLst: ['str1', 'str2', 'str3', 'str4', 'str5', ['str1', 'str2', 'str3', 'str4', 'str5']]
1.->copyLst: ['str1', 'str2', 'str3', 'str4', 'str5', ['str1', 'str2', 'str3', 'str4', 'str5']]
2.->sourceLst: ['str1', 'str2', 'str3', 'str4', 'str5', ['str1', 'str2', 'str3', 'str4', 'str5'], 'sourcestr']
2.->copyLst: ['str1', 'str2', 'str3', 'str4', 'str5', ['str1', 'str2', 'str3', 'str4', 'str5'], 'copystr']
3.->sourceLst: ['changestr', 'str2', 'str3', 'str4', 'str5', ['str1', 'str2', 'str3', 'str4', 'str5'], 'sourcestr']
3.->copyLst: ['str1', 'str2', 'str3', 'str4', 'str5', ['str1', 'str2', 'str3', 'str4', 'str5'], 'copystr']
4.->sourceLst: ['changestr', 'str2', 'str3', 'str4', 'str5', ['str1', 'str2', 'str3', 'str4', 'str5', 'testAppend'], 'sourcestr']
4.->copyLst: ['str1', 'str2', 'str3', 'str4', 'str5', ['str1', 'str2', 'str3', 'str4', 'str5', 'testAppend'], 'copystr']

  上述代码中, sourceLst和copyLst中存储的都是地址,当独自修改各个list的时候,另一个不会改变。而当修改共有的lst元素的时候,sourceLst和copyLst都会发生改变,这种情况发生在字典套字典,列表套字典,字典套列表,列表套列表,以及各种复杂数据结构的嵌套中。

六、深拷贝

  上述讲述了浅拷贝,而在实际情况中,我们希望复杂的数据结构之间完全copy,而他们之间又没有一毛钱关系。

  为此,python引入了深拷贝的概念,我们可以使用copy模块中的deepcopy方法。深拷贝会完全复制原变量相关的所有数据,在内存中生成一套完全一样的内容,在这个过程中我们队这两个变量中的一个进行任意修改都不会影响其他变量。

  浅拷贝的情况:

>>> lst1 = [1,2,3,4,[5,6,7,8]]
>>> lst2 = lst1 # 实际进行了一个浅拷贝
>>> id(lst2)
4363600648
>>> id(lst1)
4363600648
>>> lst1[0] = 100
>>> lst1
[100, 2, 3, 4, [5, 6, 7, 8]]
>>> lst2
[100, 2, 3, 4, [5, 6, 7, 8]]
>>> lst2[4][0] = 100
>>> lst1
[100, 2, 3, 4, [100, 6, 7, 8]]

  深拷贝的情况:

>>> import copy
>>> lst1 = [1,2,3,4,[5,6,7,8]]
>>> lst2 = copy.deepcopy(lst1)
>>> id(lst1)
4363594504
>>> id(lst2)
4363593928
>>> lst1[0] = 100
>>> lst2
[1, 2, 3, 4, [5, 6, 7, 8]]
>>> lst2[4][0]=100
>>> lst1
[100, 2, 3, 4, [5, 6, 7, 8]]

  从上述代码中可以看出,进行深拷贝后,lst1和lst2的地址不一样,而且两个独自修改并不影响另一个的值,他俩现在一毛钱关系都没有。

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

python3【基础】-赋值与深浅拷贝的更多相关文章

  1. python语法基础-基础-赋值与深浅拷贝

    ##################################### 预备知识一——python的变量及其存储 在详细的了解python中赋值.copy和deepcopy之前,我们还是要花一点时 ...

  2. python——赋值与深浅拷贝

    初学编程的小伙伴都会对于深浅拷贝的用法有些疑问,今天我们就结合python变量存储的特性从内存的角度来谈一谈赋值和深浅拷贝~~~ 预备知识一——python的变量及其存储 在详细的了解python中赋 ...

  3. 【python】变量的赋值、深浅拷贝

    python——赋值与深浅拷贝 https://www.cnblogs.com/Eva-J/p/5534037.html 啥都不说,看这个博主的文章!

  4. python基础知识5——赋值与深浅拷贝——整数和字符串,列表元组字典

    深浅copy 一.数字和字符串 对于 数字 和 字符串 而言,赋值.浅拷贝和深拷贝无意义,因为其永远指向同一个内存地址. 1 import copy 2 # ######### 数字.字符串 #### ...

  5. day7 基础数据类型&集合&深浅拷贝

    基础数据类型汇总: #!/usr/bin/env python # -*- coding:utf-8 -*- ''' str int ''' # str s = ' a' print(s.isspac ...

  6. python--关于赋值与深浅拷贝的认识

    作为一个自学python的小白,平时用到深浅拷贝的机会很少,因此对其也是一知半解.但是,作为一个立志成为后端工程狮的男人,眼里揉不了沙子,于是专门花时间补了补课,在此记录一下学习心得.    在讲深浅 ...

  7. python直接赋值、深浅拷贝实例剖析

    根据数据类型分为两部分进行剖析: int.str类型      list.tuple.dict类型等 1.  int.str类型 [int类型实例] >>> import copy ...

  8. python中的“赋值与深浅拷贝”

    Python中,赋值与拷贝(深/浅拷贝)之间是有差异的,这主要源于数据在内存中的存放问题,本文将对此加以探讨. 1 赋值(添加名字) 赋值不会改变内存中数据存放状态,比如在内存中存在一个名为data的 ...

  9. Python基础入门知识点——深浅拷贝

    深浅拷贝 对象引用.浅拷贝.深拷贝(拓展.难点.重点) Python中,对象的赋值,拷贝(深/浅拷贝)之间是有差异的,如果使用的时候不注意,就可能产生意外的结果 其实这个是由于共享内存导致的结果 拷贝 ...

随机推荐

  1. 题解 P1550 【[USACO08OCT]打井Watering Hole】

    题面(翻译有点问题,最后一句话) 农民John 决定将水引入到他的n(1<=n<=300)个牧场.他准备通过挖若 干井,并在各块田中修筑水道来连通各块田地以供水.在第i 号田中挖一口井需要 ...

  2. [笔记] 整除分块 & 异或性质

    整除分块 参考资料:整除分块_peng-ym OI生涯中的各种数论算法的证明 公式 求:\(\sum_{i=1}^{n}\lfloor\frac{n}{i}\rfloor\) 对于每个\(\lfloo ...

  3. 用ASP.NET Web API技术开发HTTP接口

    开发工具 Visual Studio 2013 SQL Server 2008 R2 准备工作 启动Visual Studio 2013,新建一个ASP.NET Web应用程序,命名为SimpleAP ...

  4. pytorch faster_rcnn

    代码地址:https://github.com/jwyang/faster-rcnn.pytorch 1.fasterRCNN.train():这个不是让网络进行训练,而是让module in tra ...

  5. python+requests实现接口测试 - cookies的使用 (转载)

    出自:https://www.cnblogs.com/nizhihong/p/6699492.html 在很多时候,发送请求后,服务端会对发送请求方进行身份识别,如果请求中缺少识别信息或存在错误的识别 ...

  6. 1-51单片机ESP8266学习-AT指令(开发板介绍)

    51单片机+ESP8266开发教程(AT指令篇) 开发板资源分布: 开发板部分原理图: 1--通信下载 2--51单片机 3--ESP8266(WIFI模块) 4--DHT11(温湿度传感器) 5-- ...

  7. CentOS 6.8 虚拟机安装详解

    第一步:安装 VMware 官方网站:www.vmware.com 下载百度云链接:http://pan.baidu.com/s/1bphDOWv 密码:0zix VMware 是一个虚拟 PC 的软 ...

  8. odoo之ERP系统

    odoo大纲 第一部分:数据库postgressql 大象 第二部分:ORM(API) 第三部分:客户端 用python软件写: .py文件 包含两部分:1.自定义部分,由自己写,定义类和功能. .继 ...

  9. 在AspNetCore 中 使用Redis实现分布式缓存 (转载)

    文章概念描述 分布式缓存描述:分布式缓存重点是在分布式上,相信大家接触过的分布式有很多中,像分布式开发,分布式部署,分布式锁.事物.系统 等有很多.使我们对分布式本身就有一个很明确的认识,分布式就是有 ...

  10. PuTTY+Xming实现X11的ssh转发

    1 需求分析 有些Linux程序还是不能完全离开窗口环境,或者说离开后操作不方便.其中Oracle就是这样一个程序,其工具程序大多数能够在纯命令行静默执行,如 OCI,DBCA,NetCA等,但是工作 ...