浅拷贝与深拷贝的对象引用及修改行为差异疑问
浅拷贝与深拷贝的对象引用问题解析
一、浅拷贝的行为差异原因
先看你的浅拷贝代码:
foo = [1, 2, []] bar = foo.copy() print(foo[0] is bar[0]) # True print(foo[2] is bar[2]) # True
没错,foo[0]和bar[0]确实引用同一个整数对象,foo[2]和bar[2]也引用同一个列表对象。但你后续的两个操作本质完全不同:
bar[0] = 0:重新赋值引用
这个操作不是修改原来的整数对象(整数是不可变类型,根本没法修改),而是把bar这个列表的第0个位置,从原来指向整数1的引用,改成指向新的整数0。foo列表的第0个位置依然指向原来的1,所以foo输出还是[1, 2, []]。bar[-1].append(3):修改引用的对象本身bar[-1]指向的是和foo[-1]同一个列表对象,列表是可变类型,append操作是直接修改这个列表的内容。既然两个变量都指向同一个列表,那两边都会看到修改后的结果,所以foo输出变成[1, 2, [3]]。
二、深拷贝的引用差异原因
再看深拷贝代码:
import copy foo = [1, 2, []] bar = copy.deepcopy(foo) print(foo[0] is bar[0]) # True print(foo[2] is bar[2]) # False
- 关于
foo[0] is bar[0]为True:Python对**小整数(范围通常是-5到256)**有缓存机制,会复用同一个对象实例,所以1这个整数在foo和bar里是同一个引用。如果换成一个超出这个范围的整数,比如foo = [1000, 2, []],再深拷贝的话,foo[0] is bar[0]就会是False。 - 关于
foo[2] is bar[2]为False:深拷贝会递归地拷贝所有嵌套的可变对象,这里foo[2]是一个列表,deepcopy会创建一个全新的列表对象,所以bar[2]和foo[2]是完全独立的两个对象,自然is判断为False。
内容的提问来源于stack exchange,提问作者Aaron
相关产品推荐
相关产品推荐

