Python - 可变和不可变对象
前置知识
- 在 Python 中,一切皆为对象
- Python 中不存在值传递,一切传递的都是对象的引用,也可以认为是传址
有哪些可变对象,哪些不可变对象?
- 不可变对象:字符串、元组、数字(int、float)
- 可变对象:数组、字典、集合
不可变对象和可变对象的区别?
- 可变对象:改变对象内容,对象在内存中的地址不会被改变
- 不可变对象:改变对象内容,对象在内存中的地址会被改变
从内存角度出发说下有什么区别?
不可变对象

- Python 中的变量有一个内存空间
- 具体的数据(对象)也有一个内存空间
- 而变量保存(指向)的是存储数据(对象)的内存地址,一般也叫对象引用
- 不可变对象是指对象内容本身不可变
- 变的是:改变了值,会创建新对象,然后变量改变了对象引用,指向了新对象,旧对象会被垃圾回收
可变对象

变的是:原来对象的内容,不会创建新对象,而变量也还是指向原对象
从代码角度看看区别
不可变对象-整型
a = 123
b = a
print(id(a))
print(id(b))
print(a, b) a += 2 print(id(a))
print(id(b))
print(a, b) # 输出结果
4473956912
4473956912
123 123
4473956976
4473956912
125 123
- 从前两次打印可以看到,a、b 变量保存的内存地址是同一个,他们们都保存了 123 的内存地址(123 对象的引用)
- 预期情况:在 a 做了加法赋值运算之后,既然他们一开始都是指向同一个内存地址,按道理修改 123 后,他们也应该仍然指向同一个内存地址呀,但是并没有!
- 实际情况:a 指向了新的内存地址,而 b 仍然指向旧的内存地址,所以他们的值也不一样
可以看看下面的图
首先,这是一个内存区域

原理
- 因为数字(int、float) 是不可变对象,所以不能在 123 的内存地址上直接修改数据
- 加法赋值,实际上是将原来的 123 复制了一份到新的内存地址,然后再做加法,得到一个新的值 125,最后 a 再指向新的内存地址
不可变对象-字符串
a = "test"
b = a
print(id(a))
print(id(b))
print(a, b) a += "123" print(id(a))
print(id(b))
print(a, b) # 输出结果
4455345392
4455345392
test test
4455818288
4455345392
test123 test
不可变对象-元组
a = (1, 2, 3)
b = a
print(id(a))
print(id(b))
print(a, b) a = a + a
print(id(a))
print(id(b))
print(a, b) # 输出结果
4455410240
4455410240
(1, 2, 3) (1, 2, 3)
4455359200
4455410240
(1, 2, 3, 1, 2, 3) (1, 2, 3)
可变对象列表
# 列表
a = [1, 2, 3]
b = a print(id(a))
print(id(b))
print(a, b) a += [4, 5, 6] print(a, b)
print(id(a))
print(id(b)) # 输出结果
4327665856
4327665856
[1, 2, 3, 4, 5, 6] [1, 2, 3, 4, 5, 6]
4327665856
4327665856
能看到 a 变量修改值之后,b 的值也随之修改了
可以看看下面的图

- 因为 list 是不可变对象,所以并不会将原来的值复制到新的内存地址再改变,而是直接在原来的内存地址上修改数据
- 因为 a、b 都是指向原来的内存地址的,所以 a、b 变量保存的内存地址是一致的(对象引用是一致的),当然值也是一样的啦
Python 函数的参数传递
这里先提前讲下函数的入门,因为参数传递是个挺重要的点
概念
- 开头有讲到,Python 的一切传递都是对象的引用,函数参数传递也不例外
- 当传递给函数的是一个变量,实际上传递的是变量保存的对象引用(变量指向的内存地址)
- 在函数内部修改变量时,会根据变量指向的内存地址,去修改对应的值才对,事实真是如此吗
参数传递不可变对象
# 函数
def test_no_define(age, name):
age = 123
name = "poloyy"
print(age, name) age = 1
name = "yy"
print(age, name) test_no_define(age, name)
print(age, name) # 输出结果
1 yy
123 poloyy
1 yy
参数传递可变对象
# 函数
def test_define(dicts, sets):
dicts['age'] = 24
sets.pop()
print(dicts, sets) dicts = {"age": 123}
sets = {1, 2}
print(dicts, sets) test_define(dicts, sets)
print(dicts, sets) # 输出结果
1 yy
{'age': 123} {1, 2}
{'age': 24} {2}
{'age': 24} {2}
总结
- 当函数参数传递的变量是不可变对象的时候,函数内改变变量值,函数外的变量不会随之改变
- 当函数参数传递的变量是可变对象的时候,函数内改变变量值,函数外的变量会随之改变
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 基础使用list、dict、set、可变与不可变对象
参考链接:https://www.liaoxuefeng.com/wiki/1016959663602400/1017104324028448 dict是字典,可以储存键值对类型的值,set与dict ...
- Python中的不可变对象类型与可变对象类型
https://blog.csdn.net/answer3lin/article/details/86430074 其实各个标准资料中没有说明Python有值类型和引用类型的分类,这个分类一般是C++ ...
- python基础之pip、.pyc、三元运算、进制、一切皆对象、可变与不可变类型
一.pip(下载工具==yum) 1.重点(必须掌握的) 列出已安装的包 pip list 安装要安装的包 pip install xxx 安装特定版本 pip install django==1.1 ...
- python 可变数据类型&不可变数据类型
在python中,数据类型分为可变数据类型和不可变数据类型,不可变数据类型包括string,int,float,tuple,可变数据类型包括list,dict. 所谓的可变与不可变,举例如下: > ...
- Python数据类型的可变与不可变
首先,我们需要知道在python中哪些是可变数据类型,哪些是不可变数据类型.可变数据类型:列表list和字典dict:不可变数据类型:整型int.浮点型float.字符串型string和元组tuple ...
- python的可变与不可变数据类型
<python的可变与不可变数据类型> python与C/C++不一样,它的变量使用有自己的特点,当初学python的时候,一定要记住“一切皆为对象,一切皆为对象的引用”这句话,其 ...
- Python3_函数参数传递、可变与不可变对象、变量作用域、函数返回值
参数传递: 在 python 中,类型属于对象,变量是没有类型的:(变量都仅仅是一个对象的引用,没有类型之分)a=[1,2,3] a="Runoob" 以上代码中,[1,2,3] ...
随机推荐
- javascript中的设计模式
什么是设计模式 设计模式(Design Pattern)是一套被反复使用.多数人知晓的.经过分类的.代码设计经验的总结. 使用设计模式的目的:为了代码可重用性.让代码更容易被他人理解.保证代码可靠性. ...
- Django(66)admin后台管理注册用户
前言 我们使用django创建用户可以使用注册接口的方式,也可以使用django自带的后台管理系统,这里就介绍使用后台管理系统创建用户 admin后台管理系统 在使用之前我们可以使用第三方的插件,来美 ...
- [apue] linux 文件访问权限那些事儿
前言 说到 linux 上的文件权限,其实我们在说两个实体,一是文件,二是进程.一个进程能不能访问一个文件,其实由三部分内容决定: 文件的所有者.所在的组: 文件对所有者.组用户.其它用户设置的权限访 ...
- 【模板】Linux下输出文件的对比
命令格式: diff+[参数]+[文件1或目录1]+[文件2或目录2] 命令参数: 指定要显示多少行的文本.此参数必须与-c或-u参数一并使用. -a或--text diff预设只会逐行比较文本文件. ...
- linux文件系统和日志分析
一.Linux文件系统 1.inode与block 1.概述: (1)文件数据包括元信息与实际信息 (2)文件存储在硬盘上,硬盘最小存储单位是"扇区",每个扇区存储512字节 (3 ...
- VRRP协议与原理
VRRP协议与原理 目录: 一.VRRP协议概述 1.1.VRRP协议 1.2.单网关和多网关的缺陷 1.3.VRRP基本概述 二.VRRP工作原理 2.1.VRRP主备份备份工作工程 2.2.VRR ...
- Golang使用proto3协议导致零值字段不显示
Golang使用proto3协议导致零值字段不显示 问题描述 proto协议生成的结构体如果使用直接转成json会导致零值字段不显示,这样的json是有毛病的,可以使用如下方法解决 示例Demo pa ...
- Vue(9)购物车练习
购物车案例 经过一系列的学习,我们这里来练习一个购物车的案例 需求:使用vue写一个表单页面,页面上有购买的数量,点击按钮+或者-,可以增加或减少购物车的数量,数量最少不得少于0,点击移除按钮,会 ...
- 关于Kubernetes(简称K8S)的开启及基本使用,基于Docker Desktop & WSL2
背景介绍 Kubernetes(简称k8s)已成为目前业界容器编排的事实标准,其搭配Docker可建立非常高效便捷的高可扩展.高可用应用服务架构. Kubernetes的名字来自希腊语,意思是&quo ...
- 38、mysql数据库(pymysql及事务)
38.1.python之pymysql模块: 1.说明: pymsql是Python中操作MySQL的模块,其使用方法和py2的MySQLdb几乎相同. 2.模块安装: pip install pym ...