赋值、浅拷贝、深拷贝之我理解

(一)2个为什么

先通过2个为什么来了解一下python内存中变量的存储情况。

>>> name = [1,2,3,["alex","rain"]]
>>> name2 = name.copy()     # 将原列表copy一份赋值给name2
>>> print(name)
[1, 2, 3, [‘alex‘, ‘rain‘]]
>>> print(name2)
[1, 2, 3, [‘alex‘, ‘rain‘]]
>>> 

name与name2相同

第一个为什么:

>>> name[1] = -2
>>> print(name)
[1, -2, 3, [‘alex‘, ‘rain‘]]
>>> print(name2)
[1, 2, 3, [‘alex‘, ‘rain‘]]
>>> 

name[1]改变后,name改变了而name2没有改变,为什么?

第二个为什么:

>>> name[3][0] = "ALEX"
>>> print(name)
[1, -2, 3, [‘ALEX‘, ‘rain‘]]
>>> print(name2)
[1, 2, 3, [‘ALEX‘, ‘rain‘]]
>>> 

将name[3][0]的值改后,name改变了,name2也改变了,为什么?

第一个为什么和第二个为什么都对列表进行了更改,而结果为什么不一样尼?

首先我们要清楚,列表name的元素是存在于多块内存空间中的,不是在同一块;每个元素的内存地址都是独立的。

变量name等于[1,2,3,["alex","rain"]]这个含有这些元素的列表的时候,内存中发生了2件事:一是变量name是个列表,开辟了一块内存空间;二是列表里的每一个元素各自开辟了属于自己的内存空间。name列表开辟的内存空间里存的不是元素,而是每个元素的内存地址。每一个元素比作是家的话,name列表的内存空间里存的就是邮寄到你家的包裹上的地址,是一个指向。

name2 copy name,只是copy了name中的元素(一级元素)的内存地址,即将id(1),id(2),id(3)等这些元素的内存地址复制到了name2的内存空间里了。

解答第一个为什么:

将name中的2改为-2,name内的2的内存地址会被擦除,然后将新开辟的-2的内存地址占位到此处。由于2的内存地址还被name2引用,所以2的内存不会被释放,依然存在。

对于第一个为什么,name的第一个元素为-2,name2的第一个元素为2,因为这2个的内存地址不同,所以地址所指向的数据(在内存里以十六进制数表示)就不同。内存地址不同,数据不同。

    解答第二个为什么:

   要区分清楚列表的内存地址和列表中元素的内存地址是不一样的,不要混淆

         name2 copy name的时候,copy了每个元素(一级元素)的内存地址。name中元素[‘alex‘, ‘rain‘]这个小列表的内存地址也被复制,即name中的小列表的内存地址与name2中的小列表的内存地址是一样的,也就是说name2中的小列表没有开辟新的空间,而是引用了name中小列表的空间。id(name[3]) = id(name2[3]).

第二个为什么中,对name内的小列表中的元素"alex"进行了全大写更改(过程:"ALEX"开辟了一块新的空间,将这块新空间的地址放到小列表中的索引为0的位置),即小列表(嵌套列表)内的元素的发生改变,而小列表的内存地址没有发生变化,name2中的小列表的内存地址与name中的小列表的内存地址一样,所以name中小列表的值发生变化,name2中的小列表的值也会变化。内存地址相同,指向的数据也相同

(二)赋值、浅拷贝、深拷贝

1、赋值:传递对象的引用而已,原始列表name改变,被赋值的n也会做相同的改变。(见下图,图画的不好)

2.浅拷贝:拷贝父对象,不会拷贝对象的内部的子对象。即拷贝列表name里面的一级元素的内存地址,不拷贝name里的小列表里的元素的内存地址。

3.深拷贝:copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象。即name2不仅拷贝了name中一级元素(1,2,3,["alex","rain"])的的内存地址,也拷贝了嵌套列表,["alex","rain"]里面的"alex"和"rain"的内存地址。

  

  name比作是一个容器的话,我们把name里的每样东西复制了一份放到另一个容器name2里。name里有东西丢失的话,name2里的还在,而name2这个容器是新开辟的空间。在第一个容器里的东西还未变化之前,2个不同容器装了同样的东西。

  非容器类型的没有拷贝这一说。

时间: 2024-08-28 10:16:54

赋值、浅拷贝、深拷贝之我理解的相关文章

总结:Python的赋值、深拷贝、浅拷贝有什么区别

自我总结: 1)赋值:对象赋值实际上是对象的引用. 在Python中,变量就是地址的一种表示形式,并不开辟开辟存储空间. 2)浅拷贝:只拷贝了顶层(第一层),没有拷贝子对象.所以子对象的原始数据改变,子对象会改变. 3)深拷贝:区别于浅拷贝只拷贝顶层引用,深拷贝会逐层进行拷贝,直到拷贝的所有引用都是不可变引用为止. 为什么Python默认的拷贝方式是浅拷贝? 时间角度:浅拷贝花费时间更少: 空间角度:浅拷贝花费内存更少: 效率角度:浅拷贝只拷贝顶层数据,一般情况下比深拷贝效率高. 1.pytho

JS中有关对象的继承以及实例化、浅拷贝深拷贝的奥秘

一.属性的归属问题 JS对象中定义的属性和方法如果不是挂在原型链上的方法和属性(直接通过如类似x的方式进行定义)都只是在该对象上,对原型链上的没有影响.对于所有实例共用的方法可直接定义在原型链上这样实例化的的时候就不用对每个实例定义该属性方法,所有的实例均具有该方的引用见最后的输出. function Myclass(){ this.x=" x in Myclass"; this.get=function(){}//每次实例化对象,每个对象的该方法都是独立的,是不相同的 } Mycla

$.extend()浅拷贝深拷贝

参考网址:http://bijian1013.iteye.com/blog/2255037 jQuery.extend() 函数用于将一个或多个对象的内容合并到目标对象. 注意:1. 如果只为$.extend()指定了一个参数,则意味着参数target被省略.此时,target就是jQuery对象本身.通过这种方式,我们可以为全局对象jQuery添加新的函数.2. 如果多个对象具有相同的属性,则后者会覆盖前者的属性值.   1 <!DOCTYPE html> 2 <html lang=&

Java求幂集与List的浅拷贝深拷贝问题

求幂集 使用回溯法,主要看集合里每一个元素在与不在链表中,在与不在都会创建一个新的解: import java.util.ArrayList; import java.util.List; public class p78 { public List<List<Integer>> subsets(int[] nums) { List<List<Integer>> result=new ArrayList<List<Integer>>(

Python中的赋值,浅拷贝和深拷贝的区别

赋值 内存地址的引用,所有的改变都会同步 测试代码 #coding:utf-8 import copy a=['a','b',1,[1,2,3]] b = a #对象赋值,所有改动都会联动 a.append('d') a[0]='aaa' a[3].append(4) print a print b 运行结果 ['aaa', 'b', 1, [1, 2, 3, 4], 'd'] ['aaa', 'b', 1, [1, 2, 3, 4], 'd'] 浅拷贝 str,num等深浅拷贝都一样,list

js引用类型赋值,深拷贝与浅拷贝

JS中引用类型使用等号“=” 赋值,相当于把原来对象的地址拷贝一份给新的对象,这样原来旧的对象与新的对象就指向同一个地址,改变其中一个对象就会影响另外那个对象,也就是所谓的浅拷贝.例如: var arr = ["One","Two","Three"]; var arrto = arr; arrto[1] = "test"; document.writeln("数组的原始值:" + arr + "&

关于js 浅拷贝 深拷贝 以及赋值操作。

最近同事又碰到关于深浅拷贝以及赋值的问题,今天我也研究一下记录一下,加深一下记忆. 举一个简单的例子: var people = { age:10, name:"小华", arr:[1,2,3] }; 做一个 赋值操作: var people2 = people; 然后做一个浅拷贝操作: var people3 = {}; for (var i in people){ people3[i] = people[i] }; 然后最后再做一个深拷贝操作: function deepClone

JS 数据类型、赋值、深拷贝和浅拷贝

js 数据类型 六种 基本数据类型: Boolean. 布尔值,true 和 false. null. 一个表明 null 值的特殊关键字. JavaScript 是大小写敏感的,因此 null 与 Null.NULL或其他变量完全不同. undefined. 变量未定义时的属性. Number. 表示数字,例如: 42 或者 3.14159. String. 表示字符串,例如:"Howdy" Symbol ( 在 ECMAScript 6 中新添加的类型)..一种数据类型,它的实例是

python的赋值,深拷贝和浅拷贝的区别

原文地址https://www.cnblogs.com/xueli/p/4952063.html 在python中,对象赋值实际上是对象的引用.当创建一个对象,然后把它赋给另一个变量的时候,python并没有拷贝这个对象,而只是拷贝了这个对象的引用 一般有三种方法, alist=[1,2,3,["a","b"]] (1)直接赋值,默认传递对象的引用而已,原始列表改变,被赋值的b也会做相同的改变 >>> b=alist>>> pri