Python基础-17对象引用和拷贝
2020-12-28 10:27
标签:分配 过程 python语言 示意图 返回 也会 assm lse -o ? ? 我们先来看看以下向个概念 如果有了解Java的堆栈知识(堆存储真实的数据,而栈则是存储相应引用地址),则这里所指的对象可以理解为堆,而引用则代表栈。 ? ? 对象的赋值实际上就是对象引用,创建一个对象并将其赋值给一个变量时,该变量实际是指向了该对象的引用,可使用内置函数id()查看返回值。变量名与对象之间的示意图如下所示: 示例如下所示: ? ? 在上面的例子中,本意是想修改tempB中第一个元素,而连带temA也被一起修改了。因为tempA和tempB引用的是同一个对象,修改其中任意一个变量都会影响到另一个。为了避免这种情况,必须创建对象的副本而不是创建新引用。对于像列表和字典这种容器类对象,可以使用两种拷贝操作:浅拷贝和深拷贝。 ? ? 浅拷贝将创建一个新对象,其内容是原对象中元素的引用。可以使用模块copy中的copy()函数,另外也可使用切片操作、对象的copy方法。其特点如下所示: 如果使用等号赋值时,连对象都不会重新创建。只有重新创建对象并为其赋值,才会发生浅拷贝。 ? ? 示例代码如下所示: ? ? 在上述示例中,a和b是单独的列表对象,但它们包含的元素是共享的。因此修改b的一个元素也会修改a中的对应元素。而在aa和bb中,在发生浅拷贝后,aa和bb两个对象的地址不一样,而其内部元素却指向了相同的对象。 ? ? 深拷贝将创建一个新对象并对其赋值时,原对象中的所有元素都会在新对象中重新创建一次。常用模块copy中的deepcopy()函数,其特点如下所示: ? ? 示例代码如下所示: ? ? 在打印内部地址发现,前两个元素地址没有属性改变,是因为在Python数字和字符串属于不可变对象。为提升效率,Python语言中,在内存中只存在一份不可变对象,并将其地址(即引用)赋值给其他变量。 浅拷贝和深拷贝仅仅是针对可变对象的,对于不可变对象,赋值的操作过程都是直接将引用赋值。 ? ? 现在假设有一个对象a=[ 1, 2 ,[ 3,4 ] ],有另外一个对象,分别进行=赋值、浅拷贝和深拷贝,其使用小结如下所示: ? ? 针对这种情况,有时候也被比喻为旧瓶装旧酒。 ? ? 因为元素中1和2为不可变对象,它们互不影响,给人的感觉就相当于复制了一份。这种就是浅拷贝,有时候也被比喻为新瓶装旧酒,虽然产生了新的对象,但里面的内容还是来自同一份。 ? ? 对象a和b前两个元素因是不可变对象,所会在进行深拷贝之后,地址不会进行更改。而第三个元素为可变对象,则相当创建了一个副本。所以深拷贝也可以理解为,不仅是对象自身的拷贝,对于对象中每一个子元素,也都进行同样的拷贝。针对这种情况,有时候也被比喻为新瓶装新酒 参考网址:https://segmentfault.com/a/1190000017001073 本文地址:https://www.cnblogs.com/surpassme/p/13028213.html Python基础-17对象引用和拷贝 标签:分配 过程 python语言 示意图 返回 也会 assm lse -o 原文地址:https://www.cnblogs.com/surpassme/p/13028213.html17.对象引用和拷贝
17.1 对象引用
>>> tempA=[1,3,5]
>>> tempB=tempA # tempB对tempA的引用
>>> tempB
[1, 3, 5]
>>> tempB[0]=-100 # 修改tempB的元素,tempA相应的元素也同步进行了更改
>>> tempA
[-100, 3, 5]
>>> tempB
[-100, 3, 5]
>>> id(tempA),id(tempB)
(2614814009544, 2614814009544)
>>> tempB is tempA
True
17.2 对象的拷贝
17.2.1 浅拷贝
>>> a=[1,2,[3,4]]
>>> b=list(a) # 创建a的一个浅复制
>>> b is a
False
>>> b.append(100) # 给b追加一个元素
>>> b
[1, 2, [3, 4], 100] # 修改b中的一个元素
>>> a
[1, 2, [3, 4]]
>>> b[2][0]=-98
>>> b
[1, 2, [-98, 4], 100]
>>> a # a中与b共有的元素值也会发生改变
[1, 2, [-98, 4]]
>>> id(a),id(b)
(2614813897288, 2614813796232)
>>> aa=[1,2,[3,4]]
>>> bb=aa # 直接赋值并没有发生浅拷贝
>>> id(aa),id(bb)
(1960262980168, 1960262980168)
>>> aa = list(bb)
>>> id(aa),id(bb)
(1960263019208, 1960262980168) # 发生了浅拷贝,因此两者的id也不一样
>>> id(aa[0]),id(aa[1]),id(aa[2])
(140715523797264, 140715523797296, 1960263020232)
>>> id(bb[0]),id(bb[1]),id(bb[2])
(140715523797264, 140715523797296, 1960263020232) # 虽然发生了浅拷贝,但内部元素却都指向相同的对象
17.2.2 深拷贝
>>> import copy
>>> a=[1,2,[3,4]]
>>> b=copy.deepcopy(a) # 深拷贝
>>> b is a
False
>>> b.append(100)
>>> b
[1, 2, [3, 4], 100]
>>> a
[1, 2, [3, 4]]
>>> b[2][0]=-98
>>> b
[1, 2, [-98, 4], 100]
>>> a # 在修改b之后,对a没有任何影响
[1, 2, [3, 4]]
>>> id(a),id(b)
(1960263017096, 1960263112136)
>>> aa=[1,2,[3,4]]
>>> bb=copy.deepcopy(aa) # 深拷贝
>>> id(aa),id(bb)
(2540655565384, 2540656480520) # 地址发生改变
>>> id(aa[0]),id(aa[1]),id(aa[2])
(140715523797264, 140715523797296, 2540655563912)
>>> id(bb[0]),id(bb[1]),id(bb[2])
(140715523797264, 140715523797296, 2540656401224)
17.3 小结
本文同步在微信订阅号上发布,如各位小伙伴们喜欢我的文章,也可以关注我的微信订阅号:woaitest,或扫描下面的二维码添加关注:
文章标题:Python基础-17对象引用和拷贝
文章链接:http://soscw.com/index.php/essay/38802.html