python中,tuple里的list中的元素为什么可以变,tuple到底可不可变?

众所周知,tuple与list的区别就是tuple是不可变的,是为了让程序更安全,tuple可以当作dict的key但是list不行。但tuple并不是完全不可变的,如下所示,tuple中的list的元素就是可以修改的。

>>> a = 1
>>> b = 2
>>> c = [3,4,5]
>>> d = (a,b,c)
>>> d
(1, 2, [3, 4, 5])
>>> d[2][0]=9
>>> d
(1, 2, [9, 4, 5])

首先我们需要了解python中list的一些特性:

>>> c
[9, 4, 5]
>>> c2 = c # 使用=定义一个新的list,实际上c2只是c的一个引用,修改c2中的元素,c也会同时被修改
>>> c2
[9, 4, 5]
>>> c2[0]= 99
>>> c
[99, 4, 5]
>>> id(c)
1868306709960
>>> id(c2) # 发现c2和c的id是一样的,即二者的地址相同
1868306709960
>>> c3 = [99, 4, 5]  # 定义一个新的c3,元素组成与c2一样,不过此时虽然二者内容相等,但却是不同的list对象,占用的内存地址不同
>>> c3 == c2  # == 只判断值是否相等
True
>>> c3 is c2  # is判断内存地址是否相同
False
>>> id(c3)  # 发现c3的id与c2不同
1868306685576

>>> id(c3[0])  # 查看c3里第一个元素的id
1885009424
>>> c3[0]=999  
>>> id(c3[0])  # 修改c3[0]的值后,其id也随之改变,但是c3的地址不会发生改变
1868273844016
>>> id(c3)
1868306685576

看完以上的代码,我们基本就能明白tuple中list中元素可变的原因:虽然list中的元素变了,但是list对象本身的内存地址并没有变,所以对tuple来说并没有元素发生变化。那么能否将list整体替换呢?理论上是不可行的,因为替换list本身会修改对象内存地址。看以下演示

>>> d
(1, 2, [99, 4, 5])
>>> d[2] = 3  # 不可将list整体替换
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> d[2]=c2  # 即使是将list整体替换成内存地址相同的对象也不可以,python直接不允许这种操作,以避免错误操作
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

c++里的参数传递允许传递引用和指针(所以C++难呀),而在python里,参数的传递是传递对象引用

在python中,不可改变的对象有:str,int,float,tuple;可以改变的对象有list,dict,set。可变和不可变实际上指的是对象所占用的内存地址是否可变。下面以str和list演示可变和不可变的区别。

>>> x = 'abc'
>>> type(x)
<class 'str'>
>>> y = ['a', 'b', 'c']
>>> type(y)
<class 'list'>
>>> x2 = 'abc'  # 定义一个新的x2
>>> y2 = ['a', 'b', 'c']
>>> id(x), id(x2)  # 比较两个内容相同的str的id,发现他们所占用的内存地址相同,
(1868273892576, 1868273892576)
>>> id(y), id(y2)  # 比较两个内容相同的list的id,发现不同
(1868306709832, 1868306709768)

>>> x3 = x  # 将x值赋给x3,此时二者占用的是同一个内存地址,相当于引用
>>> x3
'abc'
>>> x3 += 'd'  # 修改x3时,由于x是str类型不可变,所以x并不会跟着变,x3此时实际上是调用了新的内存地址
>>> x3
'abcd'
>>> x
'abc'
>>> y3 = y   # 对于list正相反
>>> y3
['a', 'b', 'c']
>>> y3.append('d')
>>> y3
['a', 'b', 'c', 'd']
>>> y
['a', 'b', 'c', 'd']
>>> y2
['a', 'b', 'c']

 int和float类型和str一样,dict和list一样,不过tuple虽然是不可变的,但和str不完全一样:

>>> n = (1,2,3)
>>> m = (1,2,3)
>>> id(n), id(m)  # 虽然tuple是不可变的,但是内容相同的两个tuple地址是不一样的,这和list类似。
(1868306704208, 1868306704424)

 

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值