继续打脸水货教程:关于可变对象与不可变对象

news/2024/7/19 11:37:50 标签: python, java, 爬虫, 信息可视化, 数据分析

入门教程、案例源码、学习资料、读者群

请访问: python666.cn

大家好,欢迎来到 Crossin的编程教室 !

今天这篇我要继续来打脸互联网上各种以讹传讹的水货教程。

前阵子我们聊了下Python中有关函数参数传递以及变量赋值的一些内容:Python到底是引用传递还是值传递?网上大多数教程都讲错了

先简单回顾下前文要点:

1. Python 中的变量不是装有对象的“容器”,而是贴在对象上的“标签”。
c61c9daa873d6b2c924569bfb69ecfbe.jpeg

2. 参数传递相当于一次赋值:多贴了一个标签。

3. 至于在函数内部对参数的修改是否会影响到外部变量的值,取决于你怎样修改:如果是重新赋值就不会,如果是修改对象自身内容则会。

讲到这里就有个常被提及的概念:
可变对象不可变对象

在 Python 中,
可变对象包括 list、dict、set、自定义类型等;
不可变对象包括 int、float、bool、str、tuple 等。

不可变对象不允许对自身内容进行修改。很多教程里这么说:如果我们对一个不可变对象进行赋值,实际上是生成一个新对象,再让变量指向这个对象。哪怕这个对象简单到只是数字 0 和 1:

a = 0
print('a', id(a))
a = 1
print('a', id(a))

输出:

a 4463151440
a 4463151472

这句话是没错。但这个说法其实极具误导性!难道我给一个可变对象进行赋值,就不是生成一个新对象了吗?

a = [0]
print('a', id(a))
a = [1]
print('a', id(a))

输出:

a 140286304509768
a 140286304509832

这不是也变了嘛!只要是给变量赋一个新值,就会生成一个新对象。关于这点,我们稍后还会再说。

因为对象不可变,所以为了提高效率,Python 会使用一些公用的对象:

python">a = 1
print('a', id(a))
b = 1
print('b', id(b))
print(a == b)
print(a is b)
c = 'hello world'
print('c', id(c))
d = 'hello world'
print('d', id(d))
print(c == d)
print(c is d)

输出:

a 4423761776
b 4423761776
True
True
c 4430180912
d 4430180912
True
True

这里顺便提一下 is 这个操作符。它和 == 的区别在于:== 只判断“值”是不是相等,而 is 则判断是否为同一个对象,也就是地址一致。比如:

a = 2
b = 2.0
print(a == b)
print(a is b)

输出:

True
False

这里插一句,判断一个列表是否包含某一元素的 in 操作符,你觉得它是判断 == 还是 is?猜猜这个输出是什么:

print(1.0 in [1, 2, 3])

与不可变对象的区别在于,可变对象除了被赋值外,还可以对自身内容进行修改,如:

m = [1, 2, 3]
print('m', m, id(m))
m[1] = 4
print('m', m, id(m))
m.append(5)
print('m', m, id(m))

输出:

m [1, 2, 3] 4536815752
m [1, 4, 3] 4536815752
m [1, 4, 3, 5] 4536815752

可以看到,虽然 m 的值发生了变化,但是地址没变,还是原来那个 m。

上次我也说到,很多的教程都在用可变和不可变来谈论赋值和参数传递,我觉得这些作者是不是自己也没整明白。因为他们举例不可变对象时用的是赋值,而举例可变对象又用了 list 的索引、apeend 等方法,这根本是两码事。就像我前面写的,如果大家都是赋值,那么无论是否可变,效果都是一样的,都会生成一个新对象,而不会对原变量的值产生影响。

所以理解了 Python 的赋值原理,就明白这与是否可变无关。而可变对象与不可变对象本身的不同仅在于一个可以修改变量的值,而另一个不允许。

两者在功能上的还有个区别就是:不可变对象可以作为字典 dict 的键 key,而可变对象不行。比如 list 不能作为字典的键,但 tuple 可以。

另外,明白了可变与不可变的区别,一些方法的效果也就更容易理解了:

s = 'abc'
s2 = s.replace('b', 'd')
print('s', s)
print('s2', s2)
m = [1, 2, 3]
m2 = m.reverse()
print('m', m)
print('m2', m2)

输出:

s abc
s2 adc
m [3, 2, 1]
m2 None

因为 str 是不可变对象,所以它的方法如 replacestripupper 都不可能修改原对象,只会返回一个新对象,必须重新赋值才可以。而 list 是可变对象,它的方法如 reversesortappend,都是在原有对象上直接修改,无返回值。

不过,有个特殊情况需要注意:

m = [1, 2, 3]
print('m', m, id(m))
m += [4]
print('m', m, id(m))
m = m + [5]
print('m', m, id(m))

输出

m [1, 2, 3] 4494164104
m [1, 2, 3, 4] 4494164104
m [1, 2, 3, 4, 5] 4494181128

m = m +m += 虽然是一样的结果,但 m 指向的对象却发生了变化。原因在于,前者是做了赋值操作,而后者其实是调用的 __iadd__ 方法。

如果我们就是需要产生一个 list 对象的副本,可以通过 [:]

m = [1, 2, 3]
print('m', m, id(m))
n = m[:]
print('n', n, id(n))
n[1] = 4
print('m', m)
print('n', n)

这样对 n 的修改便不再会影响到 m,因为它们已不是同一个对象。

那么如果是这样呢:

m = [1, 2, [3]]
n = m[:]
n[1] = 4
n[2][0] = 5
print(m)

猜一猜 m 的结果是什么?欢迎在评论区说下你的答案。

然后再去 Python 里执行下看看输出,是不是和预期一样,想想为什么?这个牵涉到浅拷贝、深拷贝的概念,我们下次再聊。

感谢转发点赞的各位~


_往期文章推荐_

我用什么写Python?


如需了解付费精品课程教学答疑服务

请在Crossin的编程教室内回复: 666

d23cb431e6012bb23aaa90ae04f8e968.jpeg


http://www.niftyadmin.cn/n/274892.html

相关文章

设计模式——组件协作模式之观察者模式

文章目录 前言一、“组件协作” 模式二、Observer 观察者模式1、动机2、模式定义3、伪代码示例①、第一种方案,最朴素的方式②、第二种方案,重构使得遵循DIP原则:③、进一步的小优化:④、修改使得支持多个观察者: 4、结…

个人复盘和总结 2022——2023

个人心路历程: 从2022年开始接触编程到现在已经断断续续的有一年了。回顾这一年,感觉有进步也有做的不足的地方。好的是从一开始的什么都不会,到现在的至少对计算机有点了解,从C语言到c到Linux系统编程再到Linux网络编程&#xf…

如何自制云平台,并实现远程访问控制?

除了阿里、腾讯各种云,计算机大神们都想自己搭建IoT云平台。今天小编跟大家分享一种用UbuntuEMQXNode-RED方式自制IoT云平台的方法,并实现无公网IP随时访问远程数据! 第一步 Step1搭建EMQX服务器 1.搭建IoT平台需要一个服务器,这…

C++设计模式8:组合模式

C++ 23种设计模式系列文章目录 创建型模式 第1式 工厂方法模式 第2式 抽象工厂模式 第3式 单例模式 第4式 建造者模式 第5式 原型模式 结构型模式 第6式 适配器模式 第7式 桥接模式 第8式 组合模式 第9式 装饰器模式

资讯汇总230429

230429 11:44 【大华股份:重点投入大模型和多模态方向 会持续按需扩容算力】大华股份在业绩说明会表示,GPT 的发展具有里程碑式的意义,公司会重点投入大模型和多模态方向,过去在大模型领域的算法和工程能力已经有一定的积累。先进…

文件系统和软硬链接

文章目录 一.文件系统1.了解磁盘的物理结构2.磁盘的存储结构a.磁盘读取 3.磁盘的逻辑结构a.为什么操作系统不直接使用CHS地址?b.实际IO一次的大小 4.磁盘的分区管理4.1.ext文件系统a.文件查找b.文件删除 4.2目录的属性和数据 二.软硬链接软链接的建立和删除软链接的…

symfonos 1(smtp注入webshell,配合文件文件包含)

目录 扫描 SMB 提权 扫描 SMB 让我们使用SMBMAP检查这些目录的权限。 smbmap -d workgroup -H www.example.com 可能/匿名帐户可访问。 使用smb尝试连接共享网络以访问/anonymous目录。[smb://192.168.59。129/]

【Python】【进阶篇】14、Django创建第一个项目

目录 Django创建第一个项目1. 第一个项目BookStore1) BookStore项目创建 2. Django项目配置文件1) manage.py文件2) __init__.py文件3) settings.py文件4) urls.py文件5) wsgi.py文件 Django创建第一个项目 在上一章中,我们完成了开发环境的搭建工作。 本章我们将学…