不可变容器内的可变类型

编程入门 行业动态 更新时间:2024-10-24 09:29:29
本文介绍了不可变容器内的可变类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我对修改元组成员有点困惑.以下不起作用:

>>>东西 = (['a'],)>>>东西[0] = ['b']类型错误:元组"对象不支持项目分配>>>事物(['一种'],)

但这确实有效:

>>>东西[0][0] = 'b'>>>事物(['b'],)

也有效:

>>>thing[0].append('c')>>>事物(['b', 'c'],)

不起作用,但有效(嗯?!):

>>>东西[0] + = 'd'类型错误:元组"对象不支持项目分配>>>事物(['b', 'c', 'd'],)

看似与之前的相同,但有效:

>>>e = 事物[0]>>>e + = 'e'>>>事物(['b', 'c', 'd', 'e'],)

那么游戏的规则到底是什么,什么时候可以修改元组中的内容?这似乎更像是禁止对元组成员使用赋值运算符,但最后两种情况让我感到困惑.

解决方案

您可以始终修改元组内的可变值.你用

看到的令人费解的行为>>>东西[0] + = 'd'

是由 += 引起的.+= 操作符进行就地加法,但也赋值——就地加法只对文件起作用,但赋值失败,因为元组是不可变的.这么想

>>>东西[0] = 东西[0] + 'd'

更好地解释了这一点.我们可以使用标准库中的dis模块来查看在从两个表达式生成的字节码处.使用 += 我们得到一个 INPLACE_ADD 字节码:

>>>def f(some_list):... some_list += ["foo"]...>>>dis.dis(f)2 0 LOAD_FAST 0 (some_list)3 LOAD_CONST 1 ('foo')6 BUILD_LIST 19 INPLACE_ADD10 STORE_FAST 0 (some_list)13 LOAD_CONST 0 (无)16 RETURN_VALUE

使用 + 我们得到一个 BINARY_ADD:

>>>def g(some_list):... some_list = some_list + ["foo"]>>>dis.dis(g)2 0 LOAD_FAST 0 (some_list)3 LOAD_CONST 1 ('foo')6 BUILD_LIST 19 BINARY_ADD10 STORE_FAST 0 (some_list)13 LOAD_CONST 0 (无)16 RETURN_VALUE

请注意,我们在两个的地方都得到了一个STORE_FAST.这是当您尝试存储回元组时失败的字节码 - 之前出现的 INPLACE_ADD 工作正常.

这解释了为什么不起作用,但有效"的情况将修改后的列表留在后面:元组已经引用了列表:

>>>id(东西[0])3074072428L

列表随后被 INPLACE_ADD 修改,STORE_FAST 失败:

>>>东西[0] + = 'd'回溯(最近一次调用最后一次):文件<stdin>",第 1 行,在 <module> 中类型错误:元组"对象不支持项目分配

所以元组仍然有对相同列表的引用,但列表已经就地修改:

>>>id(东西[0])3074072428L>>>东西[0]['b', 'c', 'd']

I'm a bit confused about modifying tuple members. The following doesn't work:

>>> thing = (['a'],) >>> thing[0] = ['b'] TypeError: 'tuple' object does not support item assignment >>> thing (['a'],)

But this does work:

>>> thing[0][0] = 'b' >>> thing (['b'],)

Also works:

>>> thing[0].append('c') >>> thing (['b', 'c'],)

Doesn't work, and works (huh?!):

>>> thing[0] += 'd' TypeError: 'tuple' object does not support item assignment >>> thing (['b', 'c', 'd'],)

Seemingly equivalent to previous, but works:

>>> e = thing[0] >>> e += 'e' >>> thing (['b', 'c', 'd', 'e'],)

So what exactly are the rules of the game, when you can and can't modify something inside a tuple? It seems to be more like prohibition of using the assignment operator for tuple members, but the last two cases are confusing me.

解决方案

You can always modify a mutable value inside a tuple. The puzzling behavior you see with

>>> thing[0] += 'd'

is caused by +=. The += operator does in-place addition but also an assignment — the in-place addition works just file, but the assignment fails since the tuple is immutable. Thinking of it like

>>> thing[0] = thing[0] + 'd'

explains this better. We can use the dis module from the standard library to look at the bytecode generated from both expressions. With += we get an INPLACE_ADD bytecode:

>>> def f(some_list): ... some_list += ["foo"] ... >>> dis.dis(f) 2 0 LOAD_FAST 0 (some_list) 3 LOAD_CONST 1 ('foo') 6 BUILD_LIST 1 9 INPLACE_ADD 10 STORE_FAST 0 (some_list) 13 LOAD_CONST 0 (None) 16 RETURN_VALUE

With + we get a BINARY_ADD:

>>> def g(some_list): ... some_list = some_list + ["foo"] >>> dis.dis(g) 2 0 LOAD_FAST 0 (some_list) 3 LOAD_CONST 1 ('foo') 6 BUILD_LIST 1 9 BINARY_ADD 10 STORE_FAST 0 (some_list) 13 LOAD_CONST 0 (None) 16 RETURN_VALUE

Notice that we get a STORE_FAST in both places. This is the bytecode that fails when you try to store back into a tuple — the INPLACE_ADD that comes just before works fine.

This explains why the "Doesn't work, and works" case leaves the modified list behind: the tuple already has a reference to the list:

>>> id(thing[0]) 3074072428L

The list is then modified by the INPLACE_ADD and the STORE_FAST fails:

>>> thing[0] += 'd' Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'tuple' object does not support item assignment

So the tuple still has a reference to the same list, but the list has been modified in-place:

>>> id(thing[0]) 3074072428L >>> thing[0] ['b', 'c', 'd']

更多推荐

不可变容器内的可变类型

本文发布于:2023-10-19 14:52:25,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1507851.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:容器内   类型

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!