python3-赋值与深浅拷贝(转载速查)
原链接:https://www.cnblogs.com/liushiyi/p/8195666.html
一、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