【十八】深拷贝与浅拷贝
赋值与深拷贝与浅拷贝
文章目录
- 赋值与深拷贝与浅拷贝
- 前言
- 赋值
- 浅拷贝 & 深拷贝
前言
id(object)
- 返回 object 的唯一标识符(内存地址)
赋值
- Python中, 变量定义和赋值必须是同时进行的,比如当执行程序 a = 999 是先在内存中开辟一块空间来存放数据999,然后定义变量名a来 指向这块空间的内存地址,方便我们使用变量值,所以变量名和值其实是一种引用的关联关系
- 严格来说,变量名本身没有类型,通常我们所说的变量类型指的是值的数据类型
var1 = 999
print(type(var1)) # <class 'int'>
var1 = "999"
print(type(var1)) # <class 'str'>
- 通过内置函数id()获取变量地址时,实际是返回了值的地址
var1 = 256
print(id(256))
print(id(var1)) # 同上
# 140705904571168
# 140705904571168var2 = -5
print(id(-5))
print(id(var2)) # 同上
# 140705904562816
# 140705904562816var3 = 257
print(id(257))
print(id(var3)) # 不一样
# 1684355280240
# 1684355278256var4 = -6
print(id(-6))
print(id(var4)) # 不一样
# 1684355280624
# 1684355280272
- 为了节省内存空间,解释器做了优化,如果直接执行程序文件,相同 值的变量会引用自同一个对象,而在交互式窗口运行则可以看到区别 小整数对象池:Python 为了优化速度,避免整数频繁申请和销毁内存 空间,把范围在 [-5, 256] 之间的数字放在提前建立好的小整数对象池 里面,不会被垃圾回收,在这范围内的数值如果相等,地址也就相 同,因为使用的都是同一个对象
a = 257
b = 257
print(id(a))
print(id(b))
# 1684355279312
# 1684355279280a = 256
b = 256
print(id(a))
print(id(b))
# 140705904571168
# 140705904571168a = -5
b = -5
print(id(a))
print(id(b))
# 140705904562816
# 140705904562816a = -6
b = -6
print(id(a))
print(id(b))
# 1684355278768
# 1684355280304
- 一个值可以被多个变量名引用,当变量值的引用计数(即值被关联的 次数)为0时,可认定为该值不可用,那么Python的垃圾回收机制会收 回所占用的内存空间
a = 999 # a = [1, 2, 3]
b = 999 # b = [1, 2, 3]
c = a# 变量a、c都指向第一个999, 引用计数为2
print(id(a))
print(id(c))
# 1684355278704
# 1684355278704
# 变量b指向第二个999, 引用计数为1
print(id(b)) # 1684355278416
del a # 解除a的引用, 第一个999的引用计数为-1, 为1
print(id(c)) # c还是指向第一个999 # 1684355278704c = b # 解除c的引用, 重新指向第二个999, 则第一个999的引用计数再 - 1, 为0, 被回收
# b、c都指向第二个999, 引用计数+1, 为2
print(id(b))
print(id(c))
# 1684355278416
# 1684355278416
- 当一个可变类型的数据被多个变量名引用时,如果对该原数据进行修 改,那么它所有引用都会改变
a = [1, 2, 3]
b = [1, 2, 3]
c = a# 变量a、c都指向第一个[1, 2, 3], 引用计数为2
print(id(a))
print(id(c))
# 1684355286920
# 1684355286920
# 变量b指向第二个[1, 2, 3], 引用计数为1
print(id(b)) # 1684355622984a.append(4)
print(a) # [1, 2, 3, 4]
print(c) # [1, 2, 3, 4]
print(b) # [1, 2, 3]
浅拷贝 & 深拷贝
Python 中的赋值语句不复制对象,只是建立引用关联,对于可变数据,有时 我们不希望直接对它进行修改,因为这可能会导致一些意外的情况发生,所以 我们就可以把它copy一份,对它的副本进行操作
这种copy操作又分为浅层copy和深层copy,我们所学的 list.copy()、 dict.copy()、set.copy() 和切片都属于浅层copy。在copy模块中,提供了通用 的浅层和深层copy操作
浅拷贝
- 浅层拷贝只考虑最外层的数据类型
- 如果最外层的数据类型是可变的,则(最外层)发生拷贝
- 如果最外层的数据类型是不可变的,则不发生拷贝
import copytup1 = (991, "abc")
tup2 = copy.copy(tup1) # 浅拷贝
# tup2 = tup1
print(tup1)
print(tup2)
# (991, 'abc')
# (991, 'abc')
print(id(tup1))
print(id(tup2))
# 1684355563592
# 1684355563592tup3 = (991, "abc", [])
tup4 = copy.copy(tup3) # 浅拷贝
print(tup3)
print(tup4)
# (991, 'abc', [])
# (991, 'abc', [])
print(id(tup3))
print(id(tup4))
# 1684355544480
# 1684355544480
print(id(tup3[-1]))
print(id(tup4[-1]))
# 1684355633096
# 1684355633096
import copylis1 = [991, "abc", (9, 993), [994, 995], [888, 887],{"name": "Tom"}, (996, [997, 998]), (888, (886, 886))]
lis2 = copy.copy(lis1) # 浅拷贝
print(id(lis1))
print(id(lis2))
# 1684355862600
# 1684355731272
lis1.append(9)
print(lis1)
print(lis2)
# [991, 'abc', (9, 993), [994, 995], [888, 887], {'name': 'Tom'}, (996, [997, 998]), (888, (886, 886)), 9]
# [991, 'abc', (9, 993), [994, 995], [888, 887], {'name': 'Tom'}, (996, [997, 998]), (888, (886, 886))]
print("索引0对应的id", id(lis1[0]))
print("索引0对应的id", id(lis2[0]))
# 索引0对应的id 1684355278704
# 索引0对应的id 1684355278704
print("索引1对应的id", id(lis1[1]))
print("索引1对应的id", id(lis2[1]))
# 索引1对应的id 1684252072792
# 索引1对应的id 1684252072792
print("索引2对应的id", id(lis1[2]))
print("索引2对应的id", id(lis2[2]))
# 索引2对应的id 1684355540744
# 索引2对应的id 1684355540744
print("索引3对应的id", id(lis1[3]))
print("索引3对应的id", id(lis2[3]))
# 索引3对应的id 1684355731208
# 索引3对应的id 1684355731208
print("索引4对应的id", id(lis1[4]))
print("索引4对应的id", id(lis2[4]))
# 索引4对应的id 1684355731336
# 索引4对应的id 1684355731336
print("索引5对应的id", id(lis1[5]))
print("索引5对应的id", id(lis2[5]))
# 索引5对应的id 1684355618352
# 索引5对应的id 1684355618352
print("索引6对应的id", id(lis1[6]))
print("索引6对应的id", id(lis2[6]))
# 索引6对应的id 1684355540680
# 索引6对应的id 1684355540680
print("索引7对应的id", id(lis1[7]))
print("索引7对应的id", id(lis2[7]))
# 索引7对应的id 1684355557640
# 索引7对应的id 1684355557640
print(id(lis1[6][-1]))
print(id(lis2[6][-1]))
# 1684355731400
# 1684355731400
print(id(lis1[7][-1]))
print(id(lis2[7][-1]))
# 1684355542216
# 1684355542216
lis1[3] = [994]
print(lis1)
print(lis2)
# [991, 'abc', (9, 993), [994], [888, 887], {'name': 'Tom'}, (996, [997, 998]), (888, (886, 886)), 9]
# [991, 'abc', (9, 993), [994, 995], [888, 887], {'name': 'Tom'}, (996, [997, 998]), (888, (886, 886))]lis1[3].append(999)
print(lis1)
print(lis2)
# [991, 'abc', (9, 993), [994, 999], [888, 887], {'name': 'Tom'}, (996, [997, 998]), (888, (886, 886)), 9]
# [991, 'abc', (9, 993), [994, 995], [888, 887], {'name': 'Tom'}, (996, [997, 998]), (888, (886, 886))]lis1[4].append(886)
print(lis1)
print(lis2)
# [991, 'abc', (9, 993), [994, 999], [888, 887, 886], {'name': 'Tom'}, (996, [997, 998]), (888, (886, 886)), 9]
# [991, 'abc', (9, 993), [994, 995], [888, 887, 886], {'name': 'Tom'}, (996, [997, 998]), (888, (886, 886))]lis1[5].update(age=18)
print(lis1)
print(lis2)
# [991, 'abc', (9, 993), [994, 999], [888, 887, 886], {'name': 'Tom', 'age': 18}, (996, [997, 998]), (888, (886, 886)), 9]
# [991, 'abc', (9, 993), [994, 995], [888, 887, 886], {'name': 'Tom', 'age': 18}, (996, [997, 998]), (888, (886, 886))]lis1[6][-1].pop()
print(lis1)
print(lis2)
# [991, 'abc', (9, 993), [994, 999], [888, 887, 886], {'name': 'Tom', 'age': 18}, (996, [997]), (888, (886, 886)), 9]
# [991, 'abc', (9, 993), [994, 995], [888, 887, 886], {'name': 'Tom', 'age': 18}, (996, [997]), (888, (886, 886))]
深拷贝
- 如果判断的该数据本身不可变且包含的所有数据都不可变, 则该数据不 发生拷贝
- 如果判断的该数据本身可变或者包含的数据存在可变, 则该数据发生拷贝
- 对于其中需要判断的元素分别递归的去适用前两点规则
import copytup1 = (991, "abc")
tup2 = copy.deepcopy(tup1) # 深拷贝
# tup2 = tup1
print(tup1)
print(tup2)
print(id(tup1))
print(id(tup2))
# (991, 'abc')
# (991, 'abc')
# 1684355549832
# 1684355549832tup3 = (991, "abc", [])
tup4 = copy.deepcopy(tup3) # 深拷贝
print(tup3)
print(tup4)
# (991, 'abc', [])
# (991, 'abc', [])
print(id(tup3))
print(id(tup4))
# 1684355543400
# 1684355376976
print(id(tup3[0]))
print(id(tup4[0]))
#
# 1684355280144
# 1684355280144
print(id(tup3[1]))
print(id(tup4[1]))
# 1684252072792
# 1684252072792print(id(tup3[-1]))
print(id(tup4[-1]))
# 1684355731016
# 1684355731144
import copylis1 = [991, "abc", (9, 993), [994, 995], [888, 887],{"name": "Tom"}, (996, [997, 998]), (888, (886, 886))]
lis2 = copy.deepcopy(lis1) # 深拷贝
print(id(lis1))
print(id(lis2))
# 1684355865480
# 1684355865288
lis1.append(9)
print(lis1)
print(lis2)
# [991, 'abc', (9, 993), [994, 995], [888, 887], {'name': 'Tom'}, (996, [997, 998]), (888, (886, 886)), 9]
# [991, 'abc', (9, 993), [994, 995], [888, 887], {'name': 'Tom'}, (996, [997, 998]), (888, (886, 886))]print("索引0对应的id", id(lis1[0]))
print("索引0对应的id", id(lis2[0]))
# 索引0对应的id 1684355278352
# 索引0对应的id 1684355278352
print("索引1对应的id", id(lis1[1]))
print("索引1对应的id", id(lis2[1]))
# 索引1对应的id 1684252072792
# 索引1对应的id 1684252072792
print("索引2对应的id", id(lis1[2]))
print("索引2对应的id", id(lis2[2]))
# 索引2对应的id 1684355568328
# 索引2对应的id 1684355568328
print("索引3对应的id", id(lis1[3]))
print("索引3对应的id", id(lis2[3]))
# 索引3对应的id 1684355865224
# 索引3对应的id 1684355862728
print("索引4对应的id", id(lis1[4]))
print("索引4对应的id", id(lis2[4]))
# 索引4对应的id 1684355865352
# 索引4对应的id 1684355865736
print("索引5对应的id", id(lis1[5]))
print("索引5对应的id", id(lis2[5]))
# 索引5对应的id 1684355271704
# 索引5对应的id 1684355805976
print("索引6对应的id", id(lis1[6]))
print("索引6对应的id", id(lis2[6]))
# 索引6对应的id 1684355563976
# 索引6对应的id 1684355623496
print("索引7对应的id", id(lis1[7]))
print("索引7对应的id", id(lis2[7]))
# 索引7对应的id 1684355557896
# 索引7对应的id 1684355557896
print(id(lis1[6][-1]))
print(id(lis2[6][-1]))
# 1684355865416
# 1684355865800
print(id(lis1[7][-1]))
print(id(lis2[7][-1]))
# 1684355607176
# 1684355607176lis1[3].append(999)
print(lis1)
print(lis2)
# [991, 'abc', (9, 993), [994, 995, 999], [888, 887], {'name': 'Tom'}, (996, [997, 998]), (888, (886, 886)), 9]
# [991, 'abc', (9, 993), [994, 995], [888, 887], {'name': 'Tom'}, (996, [997, 998]), (888, (886, 886))]lis1[5].update(age=18)
print(lis1)
print(lis2)
# [991, 'abc', (9, 993), [994, 995, 999], [888, 887], {'name': 'Tom', 'age': 18}, (996, [997, 998]), (888, (886, 886)), 9]
# [991, 'abc', (9, 993), [994, 995], [888, 887], {'name': 'Tom'}, (996, [997, 998]), (888, (886, 886))]lis1[6][-1].pop()
print(lis1)
print(lis2)
# [991, 'abc', (9, 993), [994, 995, 999], [888, 887], {'name': 'Tom', 'age': 18}, (996, [997]), (888, (886, 886)), 9]
# [991, 'abc', (9, 993), [994, 995], [888, 887], {'name': 'Tom'}, (996, [997, 998]), (888, (886, 886))]
【十八】深拷贝与浅拷贝相关推荐
- JavaScript学习(七十八)—实现对数据的浅拷贝和深拷贝
JavaScript学习(七十八)-实现对数据的浅拷贝和深拷贝 一.浅拷贝 浅拷贝:对于引用类型的数据只拷贝该数据的地址,这种拷贝称为浅拷贝 注意:拷贝出来的数据和原有的数据指向同一个空间,即他们操作 ...
- “约见”面试官系列之常见面试题第十八篇之深拷贝和浅拷贝得区别(建议收藏)
壹 ❀ 引 如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝,自食其力. 此篇文章中也会简 ...
- JavaScript学习(七十五)—图解浅拷贝和深拷贝
JavaScript学习(七十五)-图解浅拷贝和深拷贝 浅拷贝 浅拷贝只是拷贝一层,更深层次对象级别的只拷贝引用 Object.assign(target, ...sources);ES6新增方法可以 ...
- 【Java基础系列教程】第八章 Java面向对象详解(三)_抽象类、接口、内部类、深拷贝与浅拷贝
一.JavaBean规范 1.1 什么是JavaBean JavaBeans是Java中一种特殊的类,可以将多个对象封装到一个对象(bean)中.特点是可序列化,提供无参构造器,提供getter方法和 ...
- 如何实现数组深拷贝和浅拷贝?
这里是修真院前端小课堂,每篇分享文从 [背景介绍][知识剖析][常见问题][解决方案][编码实战][扩展思考][更多讨论][参考文献] 八个方面深度解析前端知识/技能,本篇分享的是: [如何实现数组深 ...
- Python 精选笔试面试习题—类继承、方法对象、包管理、闭包、可变类型作为默认参数、列表引用、sort与sorted、 append 和 extend、深拷贝和浅拷贝
1. 类继承 如下代码 class A(object):def show(self):print 'This is calss A'class B(A):def show(self):print 'T ...
- C++深拷贝与浅拷贝
浅拷贝就是成员数据之间的一一赋值:把值赋给一一赋给要拷贝的值.但是可能会有这样的情况:对象还包含资源,这里的资源可以值堆资源,或者一个文件..当 值拷贝的时候,两个对象就有用共同的资源,同时对资源可以 ...
- python的深拷贝与浅拷贝
对于list, set, dict来说, 直接赋值. 其实是把内存地址交给变量. 并不是复制⼀份内容. 两个变量的内容其实为一个地址,如果要在复制的同时分配新的地址则需要用到深拷贝和浅拷贝的命令 ls ...
- 详谈Javascript中的深拷贝和浅拷贝
数据复制是我们编程中经常会使用到的技术,对于普通数值数据来说,复制很简单,但是对于复杂类型比如对象的复制,就会有很多需要考虑的东西,比如我们经常说到的深拷贝和浅拷贝. 浅拷贝 复制的对象和原始对象属性 ...
最新文章
- 学习python第四天内容回顾
- bert中文预训练模型_[中文医疗预训练模型] MC-BERT
- 09-对象的定义方式
- cairosvg在linux中的安装_直接用ISO文件在linux上安装新系统
- java图片资源存放_Java编程中图片文件放哪
- php调用.net webservice,PHP调用.NET的WebService 简单实例
- SpringBoot 工程目录 整合mybatis-neo4j(注解类型)
- 计算机二级access考试是不是操作题必须到36分?,2016年计算机二级access考试题库...
- 为ASP.NET 2.0网站生成唯一程序集
- fatal error: caffe/proto/caffe.pb.h: No such file or directory
- Android菜单详解
- 怎么降低照片大小kb?
- 【前端第七课】媒体查询的语法;移动端适配相关知识点;Grid高级布局
- http 报文格式、状态码
- matlab lte rsrp,为什么选择 FieldFox 手持式分析仪?- 更宽带宽,更高精度
- 【新知实验室】体验腾讯云音视频
- 这156套PS笔刷合集!两天时间给大家盘来了!
- Python - 深度学习系列2-人脸比对 Siamese
- python无法正常启动0xc000007b_应用程序无法正常启动(0xc000007b)。
- 计算机如何恢复桌面,如何恢复计算机桌面图标不见了