我对修改元组成员有点困惑.以下不起作用:
>>>东西 = (['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_VALUEWith + 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_VALUENotice 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]) 3074072428LThe 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 assignmentSo 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']
更多推荐
不可变容器内的可变类型
发布评论