首先以一个例子来讲明一下:定义变量a = 1,使b = a。开始的状况下打印a与b都为1(显而易见,哈哈)数据结构
可是接下来,咱们作一下改动,令 a = 222,再打印a与b。函数
咦?说好的b = a呢?!怎么不同了呢?spa
这里直接揭晓答案:3d
如上图所示,a = 1操做实际上是将变量a 指向了数字1的内存地址,当进行b=a操做时,并非将a的值直接赋值给b,而是直接把变量b指向了1的内存地址。当进行a = 222时,程序又将变量a指向了222的内存地址,而此时b指向的仍然是1的内存地址,所以最终打印出来的a=222,而b=1。blog
咱们能够用下面方法来验证:内存
id()方法 能够获得变量以及其余数据类型的内存地址,从上图咱们能够看到id(a)与id(b)相等,说明在进行b=a操做时,程序进行的是将变量b指向数字1的内存地址的操做。容器
这样就比较好理解了,当进行a = 222操做的时候,a指向了222的内存地址,而此时b仍然指向的是1的内存地址,因此打印出来的值也不同了:变量
2.1列表的赋值:数据类型
这里咱们仍是以一个例子来进行说明:程序
一开始固然是一派和谐,嘿嘿!可是,当咱们试图改变l1的时候,你会发现:
当咱们将l1后面追加数字666后,打印出来的l1与l2居然同样!这与上面的结果不一样。为何会是这样的呢?
列表与变量不一样的是:当把列表[1,2,3,4,5]赋给l1的时候,l1指向的其实只是这个“列表”的内存地址,而列表中的每一个元素是有本身独立的内存地址的,与这个列表无关。而后咱们进行l2 = l1的操做时,程序执行的实际上是“将l2指向了l1指向的列表的内存地址”。
所以,不论是l1仍是l2,他们都只是指向了这个列表“容器”的地址,这个“容器”中有什么甚至作何种改变他们是不知道的。因此咱们把列表后面追加数字666后,l1与l2指向的这个“容器”里装的“元素”是如出一辙的~
咱们还能够用id()进行验证:
这里能够看到l1与l2的内存地址一致。
2.2 列表的浅拷贝:
这里仍是以一个例子开头:
这里当咱们进行l2 = l1.copy()的浅拷贝操做时,咱们会发现程序为l2新建了一个内存空间。而后咱们再来进行改变操做:
当咱们进行l1[3] = 666后,仅改变了l1里元素的值,l2仍然不变。这是由于列表中每一个元素的内存地址是与列表自己的内存地址不一样的,因此当l1与l2指向了不一样的内存地址的列表的时候,改变l1中“元素”的值l2仍然不变。这里咱们能够看看l1[3]与l2[3]的id就知道了:
能够看出l1[3]的内存地址与l2[3]的内存地址不一样,所以改变l1[3]的值不会影响l2[3]。
可是若是咱们换一个数据结构(列表嵌套列表):
这里咱们将l1的l1[4]改为了一个列表,当把l1浅拷贝给l2后,在l1与l2中是将[5,6]这个总体列表当成了原列表中的“元素”来对待的,因此l1[4]的id与l2[4]的id是相同列表的id,当咱们进行l1[4][0] = 666时,因为l1[4]与l2[4]指向的是相同的列表,因此打印出的值是同样的:
能够看出l1[4]的id与l2[4]的id是相同列表的id,因为内存地址相同因此改变其中的一个,另外的一个会跟着改变。
深拷贝,顾名思义固然是拷贝变量与原变量是独立存在的,这里直接上代码演示:
如上图所示,咱们须要先导入copy模块来进行深拷贝,函数内用copy.deepcopy()方法进行实现。拷贝出来的列表是独立存在的个体。
可是深拷贝在用的时候须要注意,因为拷贝的变量是独立存在的,因此它也会占用内存空间。若是被拷贝的数据量很大(好比占2g),那么拷贝后的数据总量将翻倍(变成4g),用的时候先规划好空