一个元祖的元素是列表的情况下修改元祖中的某个列表,会报错,但是元素修改会成功是什么原因

2017-07-10 10:14:51 +08:00
 blacklinux

假设一个元祖 t = ([1],[1,2],[1,2,3]) 执行这些操作: t[1].append(3) # 成功

t[1] += [3] # 报错 TypeError: 'tuple' object does not support item assignment,但是 t 的已经被修改成([1], [1, 2, 3], [1, 2, 3])

t[1] = t[1] + [3] # 报错,并且修改失败

这是为什么呢?

3006 次点击
所在节点    问与答
11 条回复
freetstar
2017-07-10 10:22:47 +08:00
假设一个元祖 t = ([1],[1,2],[1,2,3]) 执行这些操作:t[1].append(3) # 成功

t[1]此时是[1,2]这个列表,列表 append 操作 ok

-------------------------------------------------------------------------------------

t[1] += [3] # 报错 TypeError: 'tuple' object does not support item assignment

元组不支持赋值操作,这个可以理解。为什么能改掉列表里的内容,是不是和+=操作符有关。

等大神来解答
dozer47528
2017-07-10 10:26:02 +08:00
首先,元组不能修改,这个报错很正常

但为什么修改成功了呢!?

看上去 python 对 array += array 的内部实现是用了 append, 而不是创建一个新的 array。
这个要验证也很简单,看一下源码就行了。
lln133208
2017-07-10 10:28:11 +08:00
流畅的 Python 中有讲这个问题
sunbeams001
2017-07-10 10:30:36 +08:00
有讨论过这个问题
/t/357570
blacklinux
2017-07-10 10:31:06 +08:00
@lln133208 这个问题要如何解答?
billion
2017-07-10 10:31:22 +08:00
元组一旦创建就不能修改。任何尝试直接修改元组的行为都会报错。

但是,在 Python 中,列表是这种结构,你保存到元组中的是一个列表的 [引用] , [相当]于一个指针,它指向存放这个列表的实际位置。所以当你用 append 的时候,修改的是那个实际的列表,而这个“指针”不变。但是当你使用+号的时候,你相当于创建了一个新的列表,然后想把元组的下标为 1 的元素修改为新的“指针”,所以这个就是修改元组的行为。
dozer47528
2017-07-10 10:33:48 +08:00
看过源码了:


所以直接操作原数组的,并没有创建一个新的,所以出现了这种状况。
lln133208
2017-07-10 10:37:14 +08:00
@blacklinux 书中的意思和 6 楼差不多,最后还给出了几个建议。
blacklinux
2017-07-10 11:04:30 +08:00
@billion 懂了:

t[1].append(3) #是直接对列表进行修改,没有赋值,不报错

t[1] += [3] # 先堆栈操作,然后在赋值,由于元祖不可更改,所以赋值会失败,但由于堆栈已经操作过了,所以列表的内容还是改变了

t[1] = t[1] + [3] # 直接赋值,会失败
ETiV
2017-07-10 11:14:23 +08:00
看标题愣了一下

元祖不是买蛋糕的吗……
qyc666
2017-07-10 11:49:17 +08:00
元祖……雪月饼?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/374183

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX