python,可变对象,不可变对象,深拷贝,浅拷贝。
学习整理,若有问题,欢迎指正。
python 可变对象,不可变对象
- 可变对象
该对象所指定的内存地址上面的值可以被改变,变量被改变后,其所指向的内存地址上面的值,直接被改变,没有发生复制行为,也没有发生开辟新的内存地址行为。
python可变对象有,列表,字典,set集合
列如:

- a = ['1','2','3']
- print(id(a))
- 2275736586376
- a.append('1')
- print(a)
- ['1', '2', '3', '1']
- print(id(a))
- 2275736586376

我们可以看到,在向 a 列表内追加数据的时候,列表 a 前后的id没有发生变化,所以内存地址内,没有开辟新的空间,而是直接在原指定内存地址上面修改的。
图解:
2. 不可变对象
该对象所指定内存中的值不可以被改变,在改变某个对象的值的时候,由于其内存中的值不可以被改变,所以,会把原来的值复制一份再进行改变,这样就会计算机会开辟
一段新的内存空间来存储新的值,python 不可变对象有 int str float number,tuple,None
例如:

- c = 'Hello'
- print(id(c))
- 2237718097848
- print(c)
- Hello
- c = c + 'World'
- print(id(c))
- 2237720838960
- print(c)
- HelloWorld

我们可以看到,c变量在追加的时候,两个id是不一样的,所以内存地址会发生变化,此变化为,将c变量所指向的内存,复制一份,然后再做更改。
图解:
此时,c的内存是指向 HelloWorld的,若Hello内存,长时间没有变量指定,则垃圾回收机制会自动回收的。
3. 等于赋值,并不会产生独立的对象单独存在,而是给原来的数据块打上一个新的标签,其中一个标签值被改变的时候,另一个标签也随之改变。

- alist = [1,2,3,['a','b','c']]
- b = alist
- #此处id相同,所以指向同以内存地址
- print(id(alist))
- 2030874445768
- print(id(b))
- 2030874445768
- #向alist内追加元素
- alist.append(5)
- print(alist)
- [1, 2, 3, ['a', 'b', 'c'], 5]
- print(b)
- [1, 2, 3, ['a', 'b', 'c'], 5]
- #向alist内的列表追加元素
- alist[3].append("d")
- print(alist)
- [1, 2, 3, ['a', 'b', 'c', 'd'], 5]
- print(b)
- [1, 2, 3, ['a', 'b', 'c', 'd'], 5]
- print(id(alist))
- 2030874445768
- print(id(b))
- 2030874445768

由上面代码看出,alist所指向 [1,2,3,['a','b','c']] 内存地址,b 也是指定的[1,2,3,['a','b','c']]内存地址(id相同),所以a.append(5)后,alist变化,b也变化
图解:
由上图可以看出,无论alist做什么操作,b的内存地址都是指向alist的,所以alist的任何变化,b都会跟着变化。
4. 浅复制,浅复制分为两种情况
- 第一种情况,浅复制的值是不可变对象(数值,字符串,元组)时,与等值复制的是一样的,对象的id值与浅复制对象的id是一样的。

- import copy
- a = 'abcde'
- b = a
- print(id(a))
- 2030878234584
- print(id(b))
- 2030878234584
- c = copy.copy(a)
- print(id(c))
- 2030878234584
- #当改变a的值
- a = a + 'fg'
- print(id(a))
- 2030878515304
- #由于字符串为不可变对象,所以id(a)会发生变化,但是b,c不会发生变化,还是指向原有内存
- print(id(b))
- 2030878234584
- print(id(c))
- 2030878234584

由上面代码可以看出 b = a 其实b,a是指向同一块内存的(id)相同,c=copy.copy(a)也是和a,b指向同一块内存的(id相同),当a发生变化的时候,a会复制原有值,开辟一块新的内存
出来,此时,c与b还是指向原有内存(观察id)
图解:
- 当浅复制的值是可变对象(列表和元组)时会产生一个“不是那么独立的对象”存在。有两种情况:
- 复制的 对象中无 复杂 子对象,原来值的改变并不会影响浅复制的值,同时浅复制的值改变也并不会影响原来的值。原来值的id值与浅复制原来的值不同。
当浅复制的值是可变对象(列表,字典)时,改变的值不是 复杂子对象 代码如下:

- list1 = ['1','2','3']
- print(id(list1))
- 2030878577608
- list2 = list1
- print(id(list2))
- 2030878577608
- list3 = list1.copy()
- print(id(list2))
- 2030878577608
- #上面三者id都一致
- #然后在list1后面append一个新的元素,查看变化情况
- list1.append('4')
- print(list1)
- ['1', '2', '3', '4', '4']
- print(id(list1))
- 2030878577608
- print(list2)
- ['1', '2', '3', '4', '4']
- print(id(list2))
- 2030878577608
- print(list3)
- ['1', '2', '3']
- print(id(list3))
- 2030878531400
- #list3的值与list1,list2的值,不一样,且id也不一样了

当list2 = list1 的时候,完全指向同一块内存空间,list3 = list1.copy()的时候,list3也指向同一块内存空间,当list1发生变化的时候,list2与list1开辟出一块新的空间用来改变,list3还指向原有空间(或者相反)
图解:
- 当浅复制的值是可变对象(列表,字典)时,改变的值是 复杂子对象 代码如下:

- l1 = [1,2,['a','b']]
- l2 = l1
- l3 = copy.copy(l2)
- l4 = copy.deepcopy(l3)
- print(id(l1))
- 2030878621960
- print(id(l2))
- 2030878621960
- print(id(l3))
- 2030878622664
- print(id(l4))
- 2030878622728
- #id可以看出,l1,l2的id没有改变,但是,l3,l4的id发生了变化
- l1[2].append('a')
- print(id(l1))
- 2030878621960
- print(l1)
- [1, 2, ['a', 'b', 'a']]
- print(l3)
- [1, 2, ['a', 'b', 'a']]
- print(l4)
- [1, 2, ['a', 'b']]
- #l1[2].append('a')是改变l1内的可变列表的值,l1的id没有变化,值有变化,l3的值有变化,但是l4的值没有变化。
- l1.append(3)
- print(id(l1))
- 2030878621960
- print(l1)
- [1, 2, ['a', 'b', 'a'], 3]
- print(l2)
- [1, 2, ['a', 'b', 'a'], 3]
- print(l3)
- [1, 2, ['a', 'b', 'a']]
- print(l4)
- [1, 2, ['a', 'b']]
- #l1.append(3)是改变l1的值,l1id没有变化,l3的值没有被改变(还是和上一步的值一样),l4与l1初始值一样的。

当改变 复杂子对象中的元素时,浅拷贝值发生了变化; 当改变的值不是复杂子对象,浅拷贝的值没有发生变化。因为 浅拷贝 ,复杂子对象的保存方式是 作为 引用 方式存储的,所以修改 浅拷贝的值 和原来的值都可以 改变 复杂子对象的值。
图解:
- 深度拷贝
- 即将被复制对象完全再复制一遍作为独立的新个体单独存在。所以改变原有被复制对象不会对已经复制出来的新对象产生影响
- 上图中已经有说明了。转载
python,可变对象,不可变对象,深拷贝,浅拷贝。的更多相关文章
- Python深复制浅复制or深拷贝浅拷贝
1. copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象.(比深拷贝更加节省内存)2. copy.deepcopy 深拷贝 拷贝对象及其子对象 用一个简单的例子说明如下: >& ...
- python集合增删改查,深拷贝浅拷贝
集合 集合是无序的,不重复的数据集合,它里面的元素是可哈希的(不可变类型),但是集合本身是不可哈希(所以集合做不了字典的键)的.以下是集合最重要的两点: 去重,把一个列表变成集合,就自动去重了. 关系 ...
- Python坑系列:可变对象与不可变对象
在之前的文章 http://www.cnblogs.com/bitpeng/p/4748148.html 中,大家看到了ret.append(path) 和ret.append(path[:])的巨大 ...
- python 可变、不可变类型、深拷贝、浅拷贝理解
简介 python中数据分为可变类型,不可变类型.不同的数据类型影响着不同情况下的深浅拷贝. 下面则将简要介绍一下 可变类型 当某个数据的值发生改变时,它对应的内存地址不发生改变,常见的有列表.字典. ...
- python引用在函数传参时的体现以及可变与不可变对象的对比
今天偶然看到 vamei 老师的博客 http://www.cnblogs.com/vamei/archive/2012/07/10/2582795.html 讲的是python动态类型以及引用的事儿 ...
- 关于python的可变和不可变对象
在python中所有都是对象,在python中只有list和dict是可变对象,其他都是不可变对象. 具体参照:http://www.cnblogs.com/lovemo1314/archive/20 ...
- python中的可变与不可变对象
Python中的可变对象和不可变对象 什么是可变/不可变对象 不可变对象,该对象所指向的内存中的值不能被改变.当改变某个变量时候,由于其所指的值不能被改变,相当于把原来的值复制一份后再改变,这会开辟一 ...
- python函数参数是值传递还是引用传递(以及变量间复制后是否保持一致):取决于对象内容可变不可变
函数参数传递本质上和变量整体复制一样,只是两个变量分别为形参a和实参b.那么,a=b后,a变了,b值是否跟着变呢?这取决于对象内容可变不可变 首先解释一下,什么是python对象的内容可变不可变? p ...
- Python中的可变、不可变对象和赋值技巧序列解包
可变对象和不可变对象 在python中一切皆对象.在Python中不存在所谓的值传递调用,一切传递都是对象的引用,也可认为是传址. python中,对象分为可变(mutable)和不可变(immuta ...
- python 基础使用list、dict、set、可变与不可变对象
参考链接:https://www.liaoxuefeng.com/wiki/1016959663602400/1017104324028448 dict是字典,可以储存键值对类型的值,set与dict ...
随机推荐
- css_属性
老师的博客:https://www.cnblogs.com/liwenzhou/p/7999532.htm css的属性 整体属性的:作用于全局 width:表示宽 height:表示长 color: ...
- 【English Email】CIP payouts now in Workday
simplification简化的[ˌsɪmplɪfɪˈkeɪʃn] quota配额[ˈkwoʊtə] regional区域的[ˈriːdʒənl] mechanics技工[məˈkænɪks] ...
- HBase 是列式存储数据库吗
在介绍 HBase 是不是列式存储数据库之前,我们先来了解一下什么是行式数据库和列式数据库. 行式数据库和列式数据库 在维基百科里面,对行式数据库和列式数据库的定义为:列式数据库是以列相关存储架构进行 ...
- Installing Supervisor and Superlance on CentOS
Installing Supervisor1 and Superlance2 on CentOS/RHEL/Fedora can be a little tricky, as the versions ...
- Arduino 串口测试 电脑发数据接收后立马返回
String comdata = ""; void setup() { Serial.begin(9600); while(Serial.read()>= 0){} //cl ...
- line-height和height
1. 行高(line-height).行距.font-size分别是什么. 行高(line-height)是指文本行基线间的垂直距离. 基线(base line)并不是汉字文字的下端沿,而是英文字母“ ...
- Google第三方网站登录(JavaScript SDK)
官网:https://developers.google.com/identity/sign-in/web/ 一.创建应用 a.去谷歌控制台创建应用 网址:https://accounts.g ...
- 私有云方案——利用阿里云云解析实现DDNS
各位都是程序员,工作中是不是遇到个类似情况.在家里研究的一些开源代码或写的一些demo或试验代码,在工作中正好需要参考一下,但是在家里的电脑上. 虽然这些都可以用云 ...
- .Net Core应用框架Util介绍(一)
距离上次发文,已经过去了三年半,这几年技术更新节奏异常迅猛,.Net进入了跨平台时代,前端也被革命性的颠覆. 回顾 2015年,正当我还沉迷于JQuery + EasyUi的封装时,突然意识到技术已经 ...
- 基于Grunt构建一个的项目
没有搭建环境的,请参考<Grunt自动化构建环境搭建 >,搭建完成后 新建一个项目目录,这里建立一个“Demo”目录 运行CMD,并进入这个目录,运行 npm install grunt ...