python中的可变与不可变、深拷贝和浅拷贝

个人猜想(很遗憾失败了)

在硬盘或者系统中存在一个字符集

如果存在硬盘中,那么硬盘出厂的时候他的字符集所占用的空间就已经确定了。

如果存在于系统的话,硬盘应该在出厂的时候为系统设置一个存储系统字符集的地方。在安装系统的时候,把这个字符集放入约定的内存空间中。

当然,这个字符集不管是存在硬盘还是系统自带,硬盘中的这片内存区域是不允许改变的。所以不可变类型的原因就找到了。

文心一言告诉我,确实存在一个字符集,但并不存在于硬盘中,而是存在系统中,用于处理数据

不过可以确定的是,这些不可变数据的创建及存储是有一定规律的

测试一下

使用python输出不可变类型的内存地址

结论:
经过多次运行,这个内存地址在一个时间段内输出的内容是相同的
应该是某种机制在保护,程序结束后并不释放内存空间
而是等待一段时间的下次调用,用来节省资源的消耗

但是结果的差值都为32

a=1
b=2
print("a=",id(a))
print("b=",id(b))

"""
a= 140731726750504
b= 140731726750536

"""

"""
a= 140731562451752
b= 140731562451784
"""

使用 C语言输出不可变类型的内存地址

测试了一下C语言的,发他的内存地址是固定不会变化的

于是我想起来C语言编译型语言,于是又重新创建了一个代码相同的文件,结果竟然是相同的

#include <stdio.h>  
  
int main() {  
    int a = 1;  
    int b = 2;  
  
    printf("变量a的内存地址是:%d\n", &a);  
    printf("变量b的内存地址是:%d\n", &b);  
  
    return 0;  
}

//变量a的内存地址是:6422300
//变量b的内存地址是:6422296

尝试使用虚拟机的ubuntn系统下运行

python测试

结果显示差值为168,但是不会在一段时间内改变

a=1
b=2
print("a=",id(a))
print("b=",id(b))


"""
a= 10894368
b= 10894400
"""

C语言测试

发现每一次的结果都不同,但是每次都相差4,由此想到了系统架构是64还是32,一时间大量的疑问涌入脑中,好吧,时间有限,停止思考,疑问封存

什么是可变与不可变

可变不可变,是指内存中的那块内容(value)是否可以被改变

  • 可变类型(mutable),创建后可以继续修改对象的内容(值)

    字典、列表

  • 不可变类型(unmutable) ,一旦创建就不可修改的对象(值)

    数字, 字符串,元组

什么是深拷贝和浅拷贝

 python中的copy 模块,可以实现拷贝功能

浅拷贝(就像快捷方式)

浅拷贝:引用(地址)拷贝,并没有产生新的空间。如果拷贝的是对象,原对象和copy对象都指向同一个内存空间,只拷贝父对象,不会拷贝对象的内部的子对象

  • 不会产生新的空间
  • 源对象和副本对象指向同一空间
  • 如果拷贝的是对象,子对象不会拷贝(不产生新的空间)

用法: copy.copy(变量) 会进行拷贝

深拷贝(真正的复制)

  • 会产生新的空间
  • 能够保持各自的独立性
  • 如果拷贝的是对象,子对象也会拷贝(产生新的空间)

深拷贝:会产生新的空间。如果拷贝的是对象,原对象和copy对象都指向不同的内存空间,会拷贝对象及其子对象(会产生新的空间)

用法:copy.deepcopy(变量名)

简单可变类型的拷贝

简单可变数据类型不管是深拷贝和浅拷贝,都会产生新的空间,而且保持各自的独立性

验证

浅拷贝

import copy

list1 = [2, 4, 6]
# 浅拷贝
list2 = copy.copy(list1)
print("list1=", list1, id(list1))
print("list2=", list2, id(list2))
list1.append(8)
print("list1=", list1, id(list1))
print("list2=", list2, id(list2))
# 测试结果
""""
list1= [2, 4, 6] 2366561172928
list2= [2, 4, 6] 2366558942976
list1= [2, 4, 6, 8] 2366561172928
list2= [2, 4, 6] 2366558942976
"""

深拷贝

import copy

list1=[2,4,6]
# 深拷贝
list2=copy.deepcopy(list1)

print("list1=", list1, id(list1))
print("list2=", list2, id(list2))
list1.append(8)
print("list1=", list1, id(list1))
print("list2=", list2, id(list2))
# 测试结果
"""
list1= [2, 4, 6] 2447599320576
list2= [2, 4, 6] 2447598755904
list1= [2, 4, 6, 8] 2447599320576
list2= [2, 4, 6] 2447598755904
"""

复杂可变类型的拷贝

复杂类型的内存地址是引用

list1 = [1, 3, 5]
list2 = [2, 4, 6]

list3 = [list1, list2]

print("list1=", list1, id(list1))
print("list2=", list2, id(list2))
print("list3=", list3, id(list3))
print("list3[0]=", list3[0], id(list3[0]))

"""
嵌套只是引用
list1= [1, 3, 5] 2090564943424
list2= [2, 4, 6] 2090564397632
list3= [[1, 3, 5], [2, 4, 6]] 2090562664192
list3[0]= [1, 3, 5] 2090564943424
"""

浅拷贝(对快捷方式创建快捷方式)

  • 复杂可变类型的 浅拷贝,实际上是引用拷贝,无法保持独立性

验证

import copy

list1 = [1, 3, 5]
list2 = [2, 4, 6]

list3 = [list1, list2]

# 已知,复杂类型的内存地址是引用
# 所以对复杂类型进行浅拷贝
list4 = copy.copy(list3)

list1.append(7)
print("list1=", list1, id(list1))
print("list3=", list3, id(list3))
print("list4=", list4, id(list4))
print("list4=[0]", list4[0], id(list4[0]))

"""运行结果:在浅拷贝结束后
对简单类型进行数据的添加
复杂类型的内容会改变,浅拷贝的内容也会发生改变
而浅拷贝的地址改变了
所以浅拷贝针对复杂类型最顶层
list1= [1, 3, 5, 7] 3144178450048
list3= [[1, 3, 5, 7], [2, 4, 6]] 3144178363904
list4= [[1, 3, 5, 7], [2, 4, 6]] 3144178364544
list4=[0] [1, 3, 5, 7] 3144178450048
"""

深拷贝(真正的复制)

  • 复杂可变类型的 深拷贝,此时会产生新的内存空间

验证

import copy

list1 = [1, 3, 5]
list2 = [2, 4, 6]

list3 = [list1, list2]

# 进行深拷贝
list4 = copy.deepcopy(list3)

list1.append(7)
print("list1=", list1, id(list1))
print("list3=", list3, id(list3))
print("list4=", list4, id(list4))
print("list4=[0]", list4[0], id(list4[0]))

"""运行结果:
深拷贝将复杂类型中的简单类型数据也进行了复制
实现了完全复制
list1= [1, 3, 5, 7] 1623394860736
list3= [[1, 3, 5, 7], [2, 4, 6]] 1623394774528
list4= [[1, 3, 5], [2, 4, 6]] 1623394775104
list4=[0] [1, 3, 5] 1623394775360
"""

简单不可变类型的拷贝(都是浅拷贝)

验证

import copy


def copy_popy():
    tuple1=(1,3,5)

    # 浅拷贝
    tuple2=copy.copy(tuple1)

    print("tuple1=",tuple1,id(tuple1))
    print("tuple2=",tuple2,id(tuple2))

    """运行结果:
    tuple1= (1, 3, 5) 2239384263296
    tuple2= (1, 3, 5) 2239384263296
    """


tuple1=(1,3,5)
#深拷贝
tuple2=copy.deepcopy(tuple1)

print("tuple1=",tuple1,id(tuple1))
print("tuple2=",tuple2,id(tuple2))

"""运行结果
tuple1= (1, 3, 5) 2406599105152
tuple2= (1, 3, 5) 2406599105152
"""

复杂不可变类型的拷贝

复杂不可变类型的本质

import copy

list1=[1,3,5]
list2=[2,4,6]

tuple1=(list1,list2)

print("list1=",list1,id(list1))
print("tuple1=",tuple1,id(tuple1))
print("tuple1[0]=",tuple1[0],id(tuple1[0]))


"""运行结果
list1= [1, 3, 5] 2175399394816
tuple1= ([1, 3, 5], [2, 4, 6]) 2175399258432
tuple1[0]= [1, 3, 5] 2175399394816
"""

验证

浅拷贝

只关心最外层的数据类型是什么,如果是不可变类型,直接引用,没有办法保证数据的独立性

外层为不可变,内层为可变

import copy

list1=[1,3,5]
list2=[2,4,6]

tuple1=(list1,list2)

# 进行浅拷贝
tuple2=copy.copy(tuple1)

print("list1=",list1,id(list1))
print("tuple1=",tuple1,id(tuple1))
print("tuple1[0]=",tuple1[0],id(tuple1[0]))
print("tuple2=",tuple2,id(tuple2))
print("tuple2[0]=",tuple2[0],id(tuple2[0]))


"""运行结果
list1= [1, 3, 5] 2384705011392
tuple1= ([1, 3, 5], [2, 4, 6]) 2384704858432
tuple1[0]= [1, 3, 5] 2384705011392


tuple2= ([1, 3, 5], [2, 4, 6]) 2384704858432
tuple2[0]= [1, 3, 5] 2384705011392
"""

外层为可变,内层为不可变
import copy

list1=(1,3,5)
list2=(2,4,6)

tuple1=[list1,list2]

# 进行浅拷贝
tuple2=copy.copy(tuple1)

print("list1=",list1,id(list1))
print("tuple1=",tuple1,id(tuple1))
print("tuple1[0]=",tuple1[0],id(tuple1[0]))
print("tuple2=",tuple2,id(tuple2))
print("tuple2[0]=",tuple2[0],id(tuple2[0]))


"""运行结果
list1= (1, 3, 5) 2192295467648
tuple1= [(1, 3, 5), (2, 4, 6)] 2192295837376
tuple1[0]= (1, 3, 5) 2192295467648

tuple2= [(1, 3, 5), (2, 4, 6)] 2192295274688
tuple2[0]= (1, 3, 5) 2192295467648
"""

深拷贝

这个数据是否有可变的数据类型,如果有它就会为可变类型开辟多个空间存储数据和地址,达到保证数据独立性的作用

外层为可变类型
import copy

list1=(1,3,5)
list2=(2,4,6)

tuple1=[list1,list2]

# 进行深拷贝
tuple2=copy.deepcopy(tuple1)

print("list1=",list1,id(list1))
print("tuple1=",tuple1,id(tuple1))
print("tuple1[0]=",tuple1[0],id(tuple1[0]))
print("tuple2=",tuple2,id(tuple2))
print("tuple2[0]=",tuple2[0],id(tuple2[0]))


"""运行结果
list1= (1, 3, 5) 2050110790272
tuple1= [(1, 3, 5), (2, 4, 6)] 2050111160000
tuple1[0]= (1, 3, 5) 2050110790272


tuple2= [(1, 3, 5), (2, 4, 6)] 2050111074560
tuple2[0]= (1, 3, 5) 2050110790272
"""

外层为不可变类型 
import copy

list1 = [1, 3, 5]
list2 = [2, 4, 6]

tuple1 = (list1, list2)

# 进行深拷贝
tuple2 = copy.deepcopy(tuple1)

print("list1=", list1, id(list1))
print("tuple1=", tuple1, id(tuple1))
print("tuple1[0]=", tuple1[0], id(tuple1[0]))
print("tuple2=", tuple2, id(tuple2))
print("tuple2[0]=", tuple2[0], id(tuple2[0]))

"""运行结果
list1= [1, 3, 5] 2221492256448
tuple1= ([1, 3, 5], [2, 4, 6]) 2221492103488
tuple1[0]= [1, 3, 5] 2221492256448

tuple2= ([1, 3, 5], [2, 4, 6]) 2221492102912
tuple2[0]= [1, 3, 5] 2221492170816
"""
内外都不可变
import copy

list1 = (1, 3, 5)
list2 = (2, 4, 6)

tuple1 = (list1, list2)

# 进行深拷贝
tuple2 = copy.deepcopy(tuple1)

print("list1=", list1, id(list1))
print("tuple1=", tuple1, id(tuple1))
print("tuple1[0]=", tuple1[0], id(tuple1[0]))
print("tuple2=", tuple2, id(tuple2))
print("tuple2[0]=", tuple2[0], id(tuple2[0]))

"""运行结果
list1= (1, 3, 5) 2647937981056
tuple1= ((1, 3, 5), (2, 4, 6)) 2647938197824
tuple1[0]= (1, 3, 5) 2647937981056

tuple2= ((1, 3, 5), (2, 4, 6)) 2647938197824
tuple2[0]= (1, 3, 5) 2647937981056
"""

注意:只要是可变类型不管是深拷贝都会开辟新的空间 

切片拷贝(变量名[:])

切片拷贝,是一种浅拷贝,副本对象和原对象指向同一个空间

简单可变类型

list1 = [1, 3, 5]

list2 = list1[:]

print("list1=", list1, id(list1))
print("list2=", list2, id(list2))

list2.append(7)
print("list1=", list1, id(list1))
print("list2=", list2, id(list2))

"""运行结果
list1= [1, 3, 5] 1612210008768
list2= [1, 3, 5] 1612211181632

list1= [1, 3, 5] 1612210008768
list2= [1, 3, 5, 7] 1612211181632
"""

复杂不可变类型

list1 = [1, 3, 5]
list2 = [2, 4, 6]

tuple1=(list1,list2)

tuple2=tuple1[:]

print("list1=",list1,id(list1))
print("tuple1=",tuple1,id(tuple1))
print("tuple2=",tuple2,id(tuple2))
print("tuple1[0]=",tuple1[0],id(tuple1[0]))
print("tuple2[0]=",tuple2[0],id(tuple2[0]))
list1.append(7)
print("tuple2[0]=",tuple2[0],id(tuple2[0]))

"""运行结果得出,切片拷贝是浅拷贝
list1= [1, 3, 5] 2281363043008
tuple1= ([1, 3, 5], [2, 4, 6]) 2281364482816
tuple2= ([1, 3, 5], [2, 4, 6]) 2281364482816

tuple1[0]= [1, 3, 5] 2281363043008
tuple2[0]= [1, 3, 5] 2281363043008
tuple2[0]= [1, 3, 5, 7] 2281363043008
"""

字典拷贝 (字典名.copy())

字典提供一个copy()方法,也是浅拷贝,虽然地址发生改变,但是内部的对象仍然是链接状态

test_dict1={"age":[10,20,30]}

test_dict2=test_dict1.copy()

print("test_dict1=",test_dict1,id(test_dict1))
print("test_dict2=",test_dict2,id(test_dict2))
test_dict1["age"][0]=100

print("test_dict1=",test_dict1,id(test_dict1))
print("test_dict2=",test_dict2,id(test_dict2))

"""运行结果显示,字典拷贝为浅拷贝
test_dict1= {'age': [10, 20, 30]} 2561919905472
test_dict2= {'age': [10, 20, 30]} 2561921341312

test_dict1= {'age': [100, 20, 30]} 2561919905472
test_dict2= {'age': [100, 20, 30]} 2561921341312
"""

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/367652.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

js获取文件名或文件后缀名(扩展名)的几种方法

有时候我们需要通过含有文件名和后缀名的一个字符串中提取出该文件的文件名或文件后缀名&#xff08;扩展名&#xff09;&#xff0c;可以通过如下几种方式进行截取。 例如文件名为: var fileName"12345.txt"; 方式一&#xff1a;subtring() 用法参考博文 【js截取字…

灵伴科技(Rokid)借助 Knative 实现 AI 应用云原生 Serverless 化

作者&#xff1a;朱炜栋、元毅、子白 公司介绍 Rokid 创立于 2014 年&#xff0c;是一家专注于人机交互技术的产品平台公司&#xff0c;2018 年即被评为国家高新技术企业。Rokid 作为行业的探索者、领跑者&#xff0c;目前致力于 AR 眼镜等软硬件产品的研发及以 YodaOS 操作系…

K8s 集群可观测性-数据分流最佳实践

简介 在微服务架构下&#xff0c;一个 k8s 集群中经常会部署多套业务&#xff0c;同时也意味着不同团队、不同角色、不同的业务会在同一集群中&#xff0c;需要将不同业务的数据在不同的空间进行管理和查看。 在传统的主机环境下&#xff0c;这个是可以通过不同的主机部署 Da…

力扣每日一题 ---- 1906. 查询差绝对值的最小值

本题中&#xff0c;我们的题目求的是差值的最小值&#xff0c;我们考虑一个因素&#xff0c;当前题目中给出的数组是没有排序过的&#xff0c;那么想要求的差值&#xff0c;是不是要两两配对进行判断差值最小值。这里我们就很费时间了&#xff0c; O(N^2)的时间复杂度&#xf…

学习笔记:超详解换根法(换根DP)(匠心之作)

一.换根DP的概念 1.换根DP是什么&#xff1f; 换根DP&#xff0c;又叫二次扫描&#xff0c;是树形DP的一种。 2.换根DP能解决什么问题&#xff1f; 换根DP能解决不指定根结点&#xff0c;并且根节点的变化会对一些值产生影响的问题。例如子结点深度和、点权和等。如果要 暴力…

【数据库】分区的优点和缺点

​ &#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;数据库 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 优点&#xff1a; 缺点&#xff1a; 结语 我的其他博客 ​ 前言 数据库中的分区技术为处理大规模数据提供了一种有效的手段…

C++:输入流/输出流

C流类库简介 C为了克服C语言中的scanf和printf存在的缺点。&#xff0c;使用cin/cout控制输入/输出。 cin&#xff1a;表示标准输入的istream类对象&#xff0c;cin从终端读入数据。cout&#xff1a;表示标准输出的ostream类对象&#xff0c;cout向终端写数据。cerr&#xff…

如何远程操控vm虚拟机(finalshell版)

你是否因为虚拟机命令行操作不便而头疼&#xff1f;是否因为难以复制粘贴而烦恼&#xff1f;是否因为无法快速上传文件而烦躁&#xff1f; 别急&#xff01;现在有一个简单便捷的软件能够实现上述你所述说的所有烦恼&#xff0c;请听我细细道来~ 一、查看虚拟机的ip地址 a.首…

Unity C#高级特性 Partial 详细使用案例

文章目录 实例 1&#xff1a;分隔UI逻辑实例 2&#xff1a;Unity编辑器自动生成代码实例 3&#xff1a;数据模型分割实例 4&#xff1a;序列化扩展实例 5&#xff1a;多视图架构实例 6&#xff1a;Unity编辑器自定义 inspectors 在Unity中&#xff0c;部分类&#xff08;Partia…

Java多线程--生产者与消费者问题

文章目录 一、生产者与消费者问题&#xff08;1&#xff09;概要&#xff08;2&#xff09;案例1、案例描述及需要明确的问题2、整体框架构思3、生产者和消费者的数据共享问题4、对Clerk类里面方法的设计5、测试6、唤醒机制7、两个消费者 二、是否释放锁的操作&#xff08;1&am…

PMP备考的三个阶段及学习方法分享

PMP证书是项目管理必备的关键技能证书&#xff0c;是具备进行项目管理的重要技能体现。无论升职加薪&#xff0c;还是从事项目管理工作&#xff0c;都非常重要。 个人主要从事产品开发工作&#xff0c;开始逐渐承担一些项目经理角色&#xff0c;但目前项目管理知识薄弱&#x…

探讨深浅拷贝在js加密中的运用

深浅拷贝是JavaScript中常用的概念&#xff0c;用于复制对象或数组。它们在处理数据时有不同的用途&#xff0c;适用于不同的场景。在本文中&#xff0c;我们将详细介绍深浅拷贝的概念&#xff0c;提供案例代码&#xff0c;并探讨它们在JavaScript中的应用场景&#xff0c;以及…

@JsonFormat 和 @@DateTimeFormat 时间格式化注解详解(一篇带你解决问题)

前后数据交互过程中&#xff0c;Date类型的数据经常会出现类型映射转换的错误&#xff0c;为了达到业务的目标时间格式&#xff0c;通常会使用JsonFormat 和 DateTimeFormat&#xff0c;但是这两者有什么区别呢&#xff1f; 一、示例代码 先准备一个POJO&#xff0c;拥有Date类…

PPT录屏功能在哪?一键快速找到它!

在现代办公环境中&#xff0c;ppt的录屏功能日益受到关注&#xff0c;它不仅能帮助我们记录演示文稿的播放过程&#xff0c;还能将操作过程、游戏等内容完美录制下来。可是很多人不知道ppt录屏功能在哪&#xff0c;本文将为您介绍ppt录屏的打开方法&#xff0c;以帮助读者更好地…

本体论(ontology)在工业4.0中的应用

信息技术中的本体与哲学的本体论是不同的&#xff0c;它代表了某个专业领域的基本概念&#xff0c;它们在智能制造和工业4.0 中具有不可或缺的作用&#xff0c;为了实现人与机器&#xff0c;机器与机器之间的确定性操作。一个标准化的&#xff0c;精确定义的本体服务是非常重要…

【XR806开发板试用】xr806使用tcp socket与手机通信

本文为极术社区XR806开发板活动试用文章。 参考&#xff1a;基于星辰处理器的全志XR806开源鸿蒙开发板上手体验 搭建环境。并成功编译。 项目源码 &#xff1a; https://gitee.com/kingwho/smart-home 在同一个局域网中&#xff0c;手机与xr806连接后&#xff0c;手机 APP 每隔…

【开源】JAVA+Vue+SpringBoot实现就医保险管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 科室档案模块2.2 医生档案模块2.3 预约挂号模块2.4 我的挂号模块 三、系统展示四、核心代码4.1 用户查询全部医生4.2 新增医生4.3 查询科室4.4 新增号源4.5 预约号源 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVue…

【对象属性拷贝】⭐️按照需要转换的类型反射设置拷贝后对象的属性

背景&#xff1a; 小伙伴们大家好&#xff0c;最近开发的时候遇到一种情况&#xff0c;项目引入了全局序列化器来实现Date&#xff0c;LocalDateTime类型的字段根据时区转换&#xff0c;总体来说接口没什么要改动的&#xff0c;只要原来字段的属性是以上两种就行&#xff0c;但…

Linux/Uinx 系统编程:进程管理(3)

Linux/Uinx 系统编程&#xff1a;进程管理&#xff08;3&#xff09; 本章来讲解进程管理的最后一部分内容。 文章目录 Linux/Uinx 系统编程&#xff1a;进程管理&#xff08;3&#xff09;I/O重定向原理FILE结构体的内部结构重定向的实现过程 scanf 与 printfscanfprintf 重定…

linux 组建和卸载raid1、raid0详细操作

组raid的最好是相同容量和型号的硬盘&#xff0c;否则会有木桶效应 linux下组raid有很多细节 一、安装raid软件 deb包 apt-get install mdadm或dnf包 dnf install mdadm二、组raid1-镜像&#xff0c;组raid0-并列 raid1和raid0只有在madam命令时一点点不同&#xff0c;其他…