搞定面试之图解Python深拷贝浅拷贝

简介: 搞定面试之图解Python深拷贝浅拷贝

搞定面试之图解Python深拷贝浅拷贝

首先了解一些基本概念

「在Python中一切皆对象」,任何对象都有三个属性:唯一标识、类型、值。

例如一个字符串:

lst= "hello python!"
# 内存地址,唯一标识
print(id(lst))
# 存储类型
print(type(lst))
# 变量值
print(lst)
# 1914884325552
# <class 'str'>
# hello python!
id() ,是Python的一个内置函数,返回对象的唯一标识,用于获取对象的内存地址

「引用」:在 Python 程序中,每个对象都会在内存中申请开辟一块空间来保存该对象,该对象在内存中所在位置的地址被称为引用,使用变量名进行指代。

「赋值」:简单来说就是对于同一个对象,增加一个别名。原理就是将一个对象的地址赋值给一个变量,使得变量指向该内存地址。

a=1
b=a

img

拷贝的作用:

为了解决数据传递后被修改的问题,就需要拷贝一份副本,即使副本被修改,也不会影响原始数据 。

「不可变类型(字符串、数值型、布尔值)的深浅拷贝」

# 不可变对象的浅拷贝,以数值为例
import copy
a=5
# 浅拷贝
b=copy.copy(a)
print(id(a))
print(id(b))

# 修改a的值
a=10
print(id(a))
print(id(b))
# 140732266387232
# 140732266387232
# 140732266387392
# 140732266387232

# 不可变对象的深拷贝,以数值为例
import copy
a=5
# 深拷贝
b=copy.deepcopy(a)
print(id(a))
print(id(b))

# 修改a的值
a=10
print(id(a))
print(id(b))

# 140732266387232
# 140732266387232
# 140732266387392
# 140732266387232

img

「综上,不可变对象的拷贝,浅拷贝和深拷贝一样,对象的引用(内存地址)没有发生变化。」

「可变对象的深浅拷贝」

「1.可变对象(列表、字典、集合)的浅拷贝」

#这里以嵌套列表为例
import copy
lsta = [1, 2, 3]
lstb = [1, 2, [3, 4, 5]]
lsta1 = copy.copy(lsta) # 非嵌套浅拷贝
lstb1 = copy.copy(lstb) # 嵌套列表浅拷贝

print(id(lsta))
print(id(lsta1))
print(id(lsta[0]), id(lsta[1]),id(lsta[2]))
print(id(lsta1[0]), id(lsta1[1]), id(lsta1[2]))

# 1373054849088
# 1373054934336
# 140732266387104 140732266387136 140732266387168
# 140732266387104 140732266387136 140732266387168

print(id(lstb))
print(id(lstb1))
print(id(lstb[0]), id(lstb[2]), id(lstb[2][0]))
print(id(lstb1[0]), id(lstb1[2]), id(lstb1[2][0]))

# 2735667449472
# 2735667458368
# 140732266387104 2735667382912 140732266387168
# 140732266387104 2735667382912 140732266387168

img

浅拷贝在拷贝时,只会copy一层,在内存中开辟一个空间,存放这个copy的列表。更深的层次并没有copy,即第二层用的都是同一个内存。

「2.可变对象(列表、字典、集合)的深拷贝」

import copy
lsta = [1, 2, 3]
lstb = [1, 2, [3, 4, 5]]
lsta1 = copy.deepcopy(lsta) # 非嵌套深拷贝
lstb1 = copy.deepcopy(lstb) # 嵌套列表深拷贝

print(id(lsta))
print(id(lsta1))
print(id(lsta[0]), id(lsta[1]),id(lsta[2]))
print(id(lsta1[0]), id(lsta1[1]), id(lsta1[2]))

# 2310617518336
# 2310617599488
# 140732194690720 140732194690752 140732194690784
# 140732194690720 140732194690752 140732194690784

print(id(lstb))
print(id(lstb1))
print(id(lstb[0]), id(lstb[2]), id(lstb[2][0]))
print(id(lstb1[0]), id(lstb1[2]), id(lstb1[2][0]))

# 2310617599744
# 2310617608704
# 140732194690720 2310617532800 140732194690784
# 140732194690720 2310617608640 140732194690784

img

综上,深拷贝时,会逐层进行拷贝,遇到可变类型,就开辟一块内存复制下来,遇到不可变类型就沿用之前的引用。

因为不可变数据修改会从新开辟新的空间,所以,深拷贝数据之间的修改都不会相互影响。

总结:

  • 浅拷贝花费时间少,占用内存少,只拷贝顶层数据,拷贝效率高。
  • 对不可变对象拷贝时,浅拷贝和深拷贝的作用是一致的,不开辟新空间,相当于赋值操作。
  • 可变对象浅拷贝时,只拷贝第一层中的引用,如果元素是可变对象,并且被修改,那么拷贝的对象也会发生变化。
  • 可变对象深拷贝时,会逐层进行拷贝,遇到可变类型,就开辟一块内存复制下来。

「补充一个常考知识点」

is == 的区别」

  • is:「比较两个对象的引用(id值)是否相同,即是否指向同一个内存地址」
  • == : 「python中的比较操作符,比较两个对象的值是否相等。」
a=1
b=1
print(a == b)
print(a is b)
print(id(a))
print(id(b))
# True
# True
# 140732603438752
# 140732603438752

a = [1, 2, 3]
b = [1, 2, 3]
print(a == b)
print(a is b)
print(id(a))
print(id(b))
# True
# False
# 2926980497856
# 2926981792128

只要 a 和 b 的值相等,a == b 就会返回True,而只有 id(a) 和 id(b) 相等时,a is b 才返回 True。

因为只需要判断两个对象的id是否相同,所以is比较的效率更高,而==默认会调用对象的 __eq__方法,遍历变量中的所有元素是否相同,效率较低。

目录
相关文章
|
2月前
|
机器学习/深度学习 算法 Java
机器学习、基础算法、python常见面试题必知必答系列大全:(面试问题持续更新)
机器学习、基础算法、python常见面试题必知必答系列大全:(面试问题持续更新)
|
2月前
|
Java C++ Python
【面试宝典】深入Python高级:直戳痛点的题目演示(下)
【面试宝典】深入Python高级:直戳痛点的题目演示(下)
|
2月前
|
设计模式 Unix Python
【面试宝典】深入Python高级:直戳痛点的题目演示(上)
【面试宝典】深入Python高级:直戳痛点的题目演示(上)
|
4月前
|
API Python
python中copy模块的使用,深拷贝和浅拷贝
python中copy模块的使用,深拷贝和浅拷贝
36 0
|
5月前
|
数据采集 机器学习/深度学习 数据可视化
了解数据科学面试中的Python数据分析重点,包括Pandas(DataFrame)、NumPy(ndarray)和Matplotlib(图表绘制)。
【7月更文挑战第5天】了解数据科学面试中的Python数据分析重点,包括Pandas(DataFrame)、NumPy(ndarray)和Matplotlib(图表绘制)。数据预处理涉及缺失值(dropna(), fillna())和异常值处理。使用describe()进行统计分析,通过Matplotlib和Seaborn绘图。回归和分类分析用到Scikit-learn,如LinearRegression和RandomForestClassifier。
105 3
|
4月前
|
存储 JavaScript 前端开发
JS浅拷贝及面试时手写源码
JS浅拷贝及面试时手写源码
|
5月前
|
Python
155. 最小栈 力扣 python 空间换时间 o(1) 腾讯面试题
155. 最小栈 力扣 python 空间换时间 o(1) 腾讯面试题
|
5月前
|
Python
Python 中浅拷贝(copy)和深拷贝(deepcopy)
Python 中浅拷贝(copy)和深拷贝(deepcopy)
|
5月前
|
存储 算法 索引
1124. 表现良好的最长时间段 (python) 前缀和 分类讨论 最大长度 力扣 面试题
1124. 表现良好的最长时间段 (python) 前缀和 分类讨论 最大长度 力扣 面试题
|
7月前
|
Java 程序员 Python
python学习13-面向对象的三大特征、特殊方法和特殊属性、类的浅拷贝和深拷贝
python学习13-面向对象的三大特征、特殊方法和特殊属性、类的浅拷贝和深拷贝