python 深复制和浅复制详解
时间:2022-07-23
本文章向大家介绍python 深复制和浅复制详解,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
id(x)函数
-
id()
函数可以查看一个变量在内存中的地址
变量赋值给变量-拷贝引用
对于以下代码
>>> import copy
>>> a=[1,2,3]
>>> b=a
>>> id(a)
"""
4382960392
"""
>>> id(b)
"""
4382960392
"""
>>> id(a)==id(b) #赋值后,两者的id相同,为true。
True
>>> b[0]=222222 #此时,改变b的第一个值,也会导致a值改变。
>>> print(a,b)
[222222, 2, 3] [222222, 2, 3] #a,b值同时改变
- 此时会发现,对于b=a这条命令而言,b是a的拷贝,指向的是内存中同一块地址即
id(a)==id(b)
。 通过改变b的元素也可以起到改变a中元素的作用,同理,改变a中的元素也会改变b中的元素。
可变对象与不可变对象
- 可变对象是指,一个对象在不改变其所指向的地址的前提下,可以修改其所指向的地址中的值; 值和地址不对应(列表)
- 不可变对象是指,一个对象所指向的地址上值是不能修改的,如果你修改了这个对象的值,那么它指向的地址就改变了 值和地址相互对应(int,float,complex,long,str,unicode,tuple) , 元组 tuple就属于不可变对象
基本可变对象的深复制和浅复制
- 基本可变对象不仅仅只有列表,还有字典等,这里使用列表举个简单的例子。
a_list = [1, 2, 3]
a_shallow_list = copy.copy(a_list)
a_deep_list = copy.deepcopy(a_list)
print("id of a_list", id(a_list), "id of a_shallow_list", id(a_shallow_list), "a_deep_list", id(a_deep_list))
# id of a_list 2249250705672 id of a_shallow_list 2249201900552 a_deep_list 2249201900424
- 其均会指向一个新的地址,即a_list,a_shallow_list,a_deep_list相互之间不影响。
- 但是其中的元素是
int
类型,是不可变对象,因此其只要其中数值不变地址也不会变化。
print("id of a_list[0]", id(a_list[0]), "id of a_shallow_list[0]", id(a_shallow_list[0]), "a_deep_list[0]", id(a_deep_list[0]))
# id of a_list[0] 1887096560 id of a_shallow_list[0] 1887096560 a_deep_list[0] 1887096560
# 基本可变对象中不可变对象的地址不会改变
基本不可变对象的深复制和浅复制
- 元组 tuple是不可变对象,只要地址改变其中的值也会改变,因此 深复制和浅复制 都不会改变其中元素的地址。
a_tuple = (1, 2, 3)
a_shallow_tuple = copy.copy(a_tuple)
a_deep_tuple = copy.deepcopy(a_tuple)
# 比较基本不可变对象,深复制和浅复制区别
print("id of a_tuple", id(a_tuple), "a_shallow_tuple", id(a_shallow_tuple), "a_deep_tuple", id(a_deep_tuple))
print("id of a_tuple[0]", id(a_tuple[0]), "a_shallow_tuple[0]", id(a_shallow_tuple[0]), "a_deep_tuple[0]",
id(a_deep_tuple[0]))
# id of a_tuple 2344837083280 a_shallow_tuple 2344837083280 a_deep_tuple 2344837083280
# id of a_tuple[0] 1885130480 a_shallow_tuple[0] 1885130480 a_deep_tuple[0] 1885130480
嵌套不可变对象的深复制和浅复制
- 但是对于嵌套对象,只要其中包含 可以引用的可变对象 ,深复制就会重新分配内存创建新的对象 。由于外层是元组对象,是不可变对象,浅复制则不会重新分配内存。 这里是 深复制和浅复制的区别之一。 而这里浅复制不改变地址的操作,也就表示操纵浅复制的对象也可以对原始对象进行操作。
a1_tuple = (1, 2, (1, 2, 3), [1, 2, 3])
a1_shallow_tuple = copy.copy(a1_tuple)
a1_deep_tuple = copy.deepcopy(a1_tuple)
# 复合嵌套不可变元素的深复制和浅复制区别
print("id of a1_tuple", id(a1_tuple), "a1_shallow_tuple", id(a1_shallow_tuple), "a1_deep_tuple", id(a1_deep_tuple))
print("id of a1_tuple[3]", id(a1_tuple[3]), "a1_shallow_tuple[3]", id(a1_shallow_tuple[3]), "a1_deep_tuple[3]",
id(a1_deep_tuple[3]))
# id of a1_tuple 2498218636296 a1_shallow_tuple 2498218636296 a1_deep_tuple 2498218638776
# id of a1_tuple[3] 2498267415048 a1_shallow_tuple[3] 2498267415048 a1_deep_tuple[3] 2498218716040
嵌套可变对象的深复制和浅复制
- 这是常见的一种模式,也是网上博文最多讨论的一种模式,即外层是一个可变对象例如list,内层中也包含有可变对象list。
- 浅复制会对外层可变对象进行复制,但是对内层可变对象不会复制,也就是说内层可变对象的地址不会改变。 这时改变拷贝对象的内层元素,原有对象内层对象也会改变。
- 但是深复制不会有这种担忧,里里外外都是重新从内存中申请的空间,都是一个全新的对象。
- 可以认为对于嵌套类型结构,深复制都是重新分配空间,建立的原来完全不同的对象。
- 建议平时用深复制,不易出错~!
a1_list = [1, 2, (1, 2, 3), [1, 2, 3]]
a1_shallow_list = copy.copy(a1_list)
a1_deep_list = copy.deepcopy(a1_list)
# 复合嵌套可变元素的深复制和浅复制区别
print("id of a1_list", id(a1_list), "id of a1_shallow_list", id(a1_shallow_list), "a1_deep_list", id(a1_deep_list))
print("id of a1_list[3]", id(a1_list[3]), "id of a1_shallow_list[3]", id(a1_shallow_list[3]), "a1_deep_list[3]",
id(a1_deep_list[3]))
# id of a1_list 1453555407752 id of a1_shallow_list 1453555447432 a1_deep_list 1453555477384
# id of a1_list[3] 1453604277640 id of a1_shallow_list[3] 1453604277640 a1_deep_list[3] 1453555448968
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法