Python可变对象和不可变对象
Python中一切皆对象,每个对象都有其唯一的id,对应的类型和值,其中id指的是对象在内存中的位置。根据对象的值是否可修改分为可变对象和不可变对象。其中,
不可对象包括:数字,字符串,tuple
可变对象包括:list,dict,set
Python中的变量可以指向任意对象,可以将变量都看成是指针,保存了所指向对象的内存地址(对象的引用)。
不可变对象
对于不可变对象,如果要更新变量引用的不可变对象的值,会创建新的对象,改变对象的引用,举个例子:
In [41]: x = 1
In [42]: y = x
In [43]: print(id(x))
140719461487648
In [44]: x = 2
In [45]: print(id(y))
140719461487648
In [46]: print(id(x))
140719461487680
In [47]: print(id(2))
140719461487680
上述是int类型的一个实例,可以看到:
- 想要变量的值,会在内存中创建一个新的对象,变量指向新的对象。
- 对于值为1或者2,不管几个引用指向它,内存中都只占用了一个地址,在Python内部会通过引用计数来记录指向该地址的引用个数,当引用个数为0时会进行垃圾回收。
所以,不可变对象的优点是对于相同的对象,无论多少个引用,在内存中只占用一个地址,缺点是更新需要创建新的对象,因此效率不高。
可变对象
对于可变对象,举个例子:
In [57]: a = [1, 2]
In [58]: b = a
In [59]: print(id(a), id(b))
1961088949320 1961088949320
In [60]: a.append(3)
In [61]: print(a, b)
[1, 2, 3] [1, 2, 3]
In [62]: print(id(a), id(b))
1961088949320 1961088949320
In [63]: a = [1, 2, 3]
In [64]: print(id(a))
1961088989704
可以看到:
- 值的变化是在原有对象的基础上进行更新的,变量引用的地址没有变化。
- 对于一个变量的两次赋值操作,值相同,但是引用的地址是不同的,也就是同样值的对象,在内存中是保存了多份的,地址是不同的。
注意,我们研究可变对象的变化,研究的是同一对象,也就是可变指的是append, +=这种操作,而不包括新的赋值操作,赋值操作是会新建一个对象的。比如:
In [96]: a = [1, 2, 3]
In [97]: b = a
In [98]: a = [1]
In [99]: b
Out[99]: [1, 2, 3]
参数传递问题
因为可变对象和不可变对象的特性,因此在参数传递上需要注意,详情可参考 我的回答
深拷贝和浅拷贝
首先,举个例子:
In [69]: data = [{'name': 'a', 'deleted': True}, {'name' : 'b', 'deleted': False}, {'name': 'c', 'deleted': False}]
In [70]: print(data)
[{'name': 'a', 'deleted': True}, {'name': 'b', 'deleted': False}, {'name': 'c', 'deleted': False}]
In [71]: def add(data_list):
...: for item in data_list:
...: if item.get('deleted'):
...: data_list.remove(item)
...: return data_list
...:
In [72]: add_result = add(data)
In [73]: print(add_result)
[{'name': 'b', 'deleted': False}, {'name': 'c', 'deleted': False}]
In [74]: print(data)
[{'name': 'b', 'deleted': False}, {'name': 'c', 'deleted': False}]
你会发现调用了add方法之后,data已经变了,在之后的代码中你已经无法再使用原来的data了,具体的原因在参数传递那个问题中我有说明。
但是,当你希望在add方法中并不会修改data的值,要怎么做呢?
这时候,你需要了解下深拷贝和浅拷贝:
深拷贝和浅拷贝的概念:
- 浅拷贝(shallow copy):构造一个新的对象并将原对象中的引用插入到新对象中,只拷贝了对象的地址,而不对对应地址所指向的具体内容进行拷贝,也就是依然使用原对象的引用。实现方式包括:工厂函数(list, set等)、切片,copy模块的copy方法。
- 深拷贝(deep copy):复制了对象的和引用,深拷贝得到的对象和原对象是相互独立的。实现方式:copy模块的deepcopy方法。
所以,上述代码可按需更新为:
def add(data_list):
ret_data_list = deepcopy(data_list)
for item in ret_data_list:
if item.get('deleted'):
ret_data_list.remove(item)
return ret_data_list
以上。
Python可变对象和不可变对象的更多相关文章
- 【Python】可变对象和不可变对象
Python在heap中分配的对象分成两类:可变对象和不可变对象.所谓可变对象是指,对象的内容是可变的,例如list.而不可变的对象则相反,表示其内容不可变. 不可变对象:int,string,flo ...
- Python 可变对象和不可变对象
具体可以看这里:http://thomaschen2011.iteye.com/blog/1441254 不可变对象:int,string,float,tuple 可变对象 :list,dicti ...
- Python中的可变对象和不可变对象
Python中的可变对象和不可变对象 什么是可变/不可变对象 不可变对象,该对象所指向的内存中的值不能被改变.当改变某个变量时候,由于其所指的值不能被改变,相当于把原来的值复制一份后再改变,这会开辟一 ...
- python,可变对象,不可变对象,深拷贝,浅拷贝。
学习整理,若有问题,欢迎指正. python 可变对象,不可变对象 可变对象 该对象所指定的内存地址上面的值可以被改变,变量被改变后,其所指向的内存地址上面的值,直接被改变,没有发生复制行为,也没有发 ...
- python函数默认参数为可变对象的理解
1.代码在执行的过程中,遇到函数定义,初始化函数生成存储函数名,默认参数初识值,函数地址的函数对象. 2.代码执行不在初始化函数,而是直接执行函数体. 代码实例 这要从函数的特性说起,在 Python ...
- python 中的可变对象与不可变对象
近日辞职待工,没有实际的项目与大家分享.暂写写在实际运用python中遇到的关于可变对象和不可变对象的坑. 首先我们需要明确一个概念,在python中一且皆对象.我们一般定义一个变量a=0,其实质a是 ...
- python可变对象与不可变对象的差别
一.可变对象和不可对象 Python在heap中分配的对象分成两类:可变对象和不可对象.所谓可变对象是指,对象的内容可变,而不可变对象是指内容不可变. 不可变对象:int.string.float ...
- python学习(28) 浅谈可变对象的单例模式设计
python开发,有时候需要设计单例模式保证操作的唯一性和安全性.理论上python语言底层实现和C/C++不同,python采取的是引用模式,当一个对象是可变对象,对其修改不会更改引用的指向,当一个 ...
- Python入门之python可变对象与不可变对象
本文分为如下几个部分 概念 地址问题 作为函数参数 可变参数在类中使用 函数默认参数 类的实现上的差异 概念 可变对象与不可变对象的区别在于对象本身是否可变. python内置的一些类型中 可变对象: ...
- python可变对象与不可变对象
可变/不可变对象定义 不可变对象 该对象所指向的内存中的值不能被改变.当改变某个变量时候,由于其所指的值不能被改变,相当于把原来的值复制一份后再改变,这会开辟一个新的地址,变量再指向这个新的地址. 可 ...
随机推荐
- 标准库 xml
xml处理模块 xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单,不过,古时候,在json还没诞生的黑暗年代,大家只能选择用xml呀,至今很多传统公司如金融 ...
- MongoDB学习(四):通过Java使用MongoDB
环境配置 在Java项目中使用MongoDB,需要在项目中引入mongo.jar这个包.下载地址:下载 请尽量下载较新的版本,本文用的是2.10.1. 连接MongoDB public synchro ...
- 图论--网络流--最大流 HDU 3572 Task Schedule(限流建图,超级源汇)
Problem Description Our geometry princess XMM has stoped her study in computational geometry to conc ...
- docker 安装centos7并SSH远程连接
1.安装centos7 镜像 1.搜索并拉取centos镜像(默认最新镜像) docker search centos docker pull centos 2.建立本机对应docker-centos ...
- java权限设计思考
1.粗粒度权限设计与细粒度权限设计 粗粒度(Coarse-graind) 表示类别级,即仅考虑对象的类别(the type of object),不考 ...
- Python第三方库之Numpy库
概述 Numpy 最基本的库,是用于处理含有同种元素的多维数组运算的第三方库 —科学计算包,python数据分析及科学计算的基础库,几乎支撑所有其他库 —支持N维数组运算.处理大型矩阵.成熟的广播函 ...
- IDEA编写快捷生成代码
转载于:https://www.jianshu.com/p/029c2de5c612 1. psvm //生成main方法: public static void main(String[] args ...
- matlab基础知识总结
- Elasticsearch系列---Term Vector工具探查数据
概要 本篇主要介绍一个Term Vector的概念和基本使用方法. term vector是什么? 每次有document数据插入时,elasticsearch除了对document进行正排.倒排索引 ...
- SpringCloudStream学习(一)RabbitMQ基础
应公司大佬要求,学习一下SpringCloudStream,作为技术储备.这几天也看了这方面的资料,现在写一篇笔记,以做总结.文章会从RabbitMQ基础讲起,到SpringCloudStream结束 ...