众所周知,python的tuple对象是不可变对象,创建之后就是不可变对象,无法修改。
1 | s = (1, 2, 3) |
那么如果是这样修改呢?
1 | a = 1 |
为什么会这样?很简单,python是强类型语言,但是同是又是动态语言,动态语言使得变量名像标签一样,被“贴”到了变量对象上 s = (a, b, c)
的时候,已经用a,b,c三个所贴的对象,初始化了一个tuple s对象,之后只不过又把a这个标签贴到了一个字符串对象而已。所以s当然不会变了。
但是如果这个tuple里面放了一些list,那么list里面的值能不能修改呢?
实验一下,就会发现是可以修改的。
1 | def foo(): |
你会发现t的值确实发生变化了,实际上这有点类似于c++中常量指针。
指针常量是指针的常量,它是不可改变地址的指针,但可以对它所指向的内容进行修改。
1 | int a = 0; |
这样p就不能被指向别的内容了,但是p本身指向的内容是可以修改的。
你可以想象,tuple就像是一个维护了n个不可改变的标签的容器。
有趣的题目
接下来来看此片博客的重头戏,先看此题目:
下面这个操作会获得什么结果:
1 | t = (1, 2, [30, 40]) |
以下是四个选项:
- t = (1, 2, [30, 40, 50, 60])
- TypeError
- 都不是
- 1,2都发生
答案是4,实际上,它会抛异常TypeError: 'tuple' object does not support item assignment
,告诉你tuple是不可变的类型,然后t实际上又发生了改变。
原因就是 +=
这个操作,实际上发生了类似如下的故事:
1 | temp = t[2] |
更深入的理解
关键还要区分,在python中, a = a + b
和 a += b
是两个不同的概念。
‘+’代表连接操作,其结果是创建了一个新的列表。
而’+=’实际上是把新列表添加到了旧有列表里,类似extend。
所以上题改成t[2] = t[2] + [50, 60]就玩不了了,会直接报错。
当然改成 t[2].extend([50,60])不会报错,看来+=和extend,看起来效果是一样的,但实际上并不完全等价。