浅拷贝和深拷贝
赋值操作的认知:
1 赋值是将一个对象的地址给一个变量,让该变量指向该地址。
2 修改不可变对象(str, tuple, int 等)需要开辟新空间
3 修改可变对象(list,dict, set 等)不需要开辟新空间
不可变对象赋值:
a = 100 b = a print(id(a), id(b)) b = 200 print(id(a), id(b))
结果:
4297647584 4297647584 4297647584 4297650784
可变对象赋值:
a = {'name': '张飞龙'} b = a print(id(a), id(b)) b['age'] = 26 print(id(a), id(b)) print(a, b)
结果:
4301088808 4301088808 4301088808 4301088808 {'name': '张飞龙', 'age': 26} {'name': '张飞龙', 'age': 26}
浅拷贝:
概念:仅仅复制了容器中元素的地址,是对一个对象的顶层拷贝。
理解:拷贝了引用,没有拷贝内容
浅拷贝实现方式:1 使用copy模块中的copy函数
2 使用切片操作
3 使用工厂函数 (list,set,dict)
示例:
import copy life = ['life', 26, ['Python', "Php", "JavaScript"]] lifer = copy.copy(life) print(id(life), id(lifer))
执行结果:
4320537224 4320558344
拷贝之后的lifer的id和之前的不同,所以浅拷贝的 时候是在为lifer开辟了新的空间
继续上面的示例
import copy life = ['life', 26, ['Python', "Php", "JavaScript"]] lifer = copy.copy(life) print(id(life), id(lifer)) life[2].append('张飞龙') print(life) print(lifer)
执行结果:
['life', 26, ['Python', 'Php', 'JavaScript', '张飞龙']] ['life', 26, ['Python', 'Php', 'JavaScript', '张飞龙']]
分析:对life的第三项进行了修改,追加了字符串‘张飞龙’,此时我们发现两个变量都发生了改变。
继续:
import copy life = ['life', 26, ['Python', "Php", "JavaScript"]] lifer = copy.copy(life) print(id(life), id(lifer)) life[2].append('张飞龙') print(life) print(lifer) lifer.append('C++') print(life) print(lifer)
最后两行打印的结果:
['life', 26, ['Python', 'Php', 'JavaScript', '张飞龙']] ['life', 26, ['Python', 'Php', 'JavaScript', '张飞龙'], 'C++']
再加最后两行代码:
for i in life: print(id(i)) for i in lifer: print(id(i))
结果:
4301108200 4297645216 4323572488 4301108200 4297645216 4323572488 4323554336
浅拷贝的存储结果如下图,我们发现,浅拷贝实际上是将原来的数据中存储的地址进行了拷贝,存储到一块内存空间中,并且将地址赋值给了lifer
解释:
正常情况下,由于lifer的每个元素存储的是life元素的每块空间的地址,所以当改变life元素值的时候,lifer中的元素也随之改变,因为第三个是列表,为可变类型的变量,所以不会在内存中新开辟空间,当我们在lifer中追加c++的时候,并不影响。
深拷贝:
概念:深拷贝是对于一个对象所有层次的拷贝(递归)
理解:完全拷贝了一个容器的副本,容器内部元素地址都不一样
深拷贝实现方式:1 使用copy模块中的deepcopy函数
还是同样的示例:
import copy life = ['life', 26, ['Python', "Php", "JavaScript"]] lifer = copy.deepcopy(life) print(id(life), id(lifer)) for i in life: print(id(i)) for i in lifer: print(id(i))
执行结果:
4333120136 4333141256 4301108200 4297645216 4333120264 4301108200 4297645216 4333162824
内存下图
浅拷贝和深拷贝总结:
1 对于不可变类型的数据,不存在深拷贝和浅拷贝一说,因为他们都是固定的内存地址。
2 python中的对象赋值都是对对象引用的传递,就是说是对象内存地址对引用。
3 使用copy.copy()可以对对象进行浅拷贝,只复制对象中元素的地址。
4 如果需要复制一个对象中的所有元素,请使用copy.deepcopy()。
5 如果元组中只有不可变类型,则不能进行拷贝。