附加到元组中定义的列表 - 这是一个错误吗? [英] Append to a list defined in a tuple - is it a bug?

查看:28
本文介绍了附加到元组中定义的列表 - 这是一个错误吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我有这个代码:

tup = ([1,2,3],[7,8,9])tup[0] += (4,5,6)

产生此错误:

TypeError: 'tuple' 对象不支持项目分配

虽然这段代码:

tup = ([1,2,3],[7,8,9])尝试:tup[0] += (4,5,6)除了类型错误:打印 tup

打印:

([1, 2, 3, 4, 5, 6], [7, 8, 9])

这种行为是预期的吗?

注意

我意识到这不是一个非常常见的用例.然而,虽然错误在意料之中,但我没想到列表会发生变化.

解决方案

是的,这是意料之中的.

元组不能改变.元组与列表一样,是指向其他对象的结构.它不关心这些对象是什么.它们可以是字符串、数字、元组、列表或其他对象.

因此,对元组中包含的对象之一执行任何操作,包括附加到该对象(如果它是列表)都与元组的语义无关.

(想象一下,如果您编写了一个类,其中的方法会导致其内部状态发生变化.您不会期望根据对象的存储位置在对象上调用这些方法是不可能的.

或者另一个例子:

<预><代码>>>>l1 = [1, 2, 3]>>>l2 = [4, 5, 6]>>>t = (l1, l2)>>>l3 = [l1, l2]>>>l3[1].append(7)

一个列表和一个元组引用的两个可变列表.我是否可以做最后一行(答案:是).如果您认为答案是否定的,为什么不呢?t 是否应该改变 l3 的语义(答案:否).

如果你想要一个不可变的顺序结构对象,它应该一直是元组.

为什么会出错?

这个例子使用了中缀运算符:

<块引用>

许多操作都有就地"版本.以下功能提供比通常更原始的就地运算符访问语法确实;例如,语句 x += y 等价于 x =operator.iadd(x, y).另一种表达方式是说 z =operator.iadd(x, y) 等价于复合语句 z = x;z+= y.

https://docs.python.org/2/library/operator.html

所以:

l = [1, 2, 3]tup = (l,)tup[0] += (4,5,6)

相当于:

l = [1, 2, 3]tup = (l,)x = tup[0]x = x.__iadd__([4, 5, 6]) # 类似扩展,但返回 x 而不是 Nonetup[0] = x

__iadd__ 行成功,修改第一个列表.所以名单已经改变了.__iadd__ 调用返回变异列表.

第二行尝试将列表分配回元组,但失败了.

因此,在程序结束时,列表已扩展但+= 操作的第二部分失败.具体见这个问题.

So I have this code:

tup = ([1,2,3],[7,8,9])
tup[0] += (4,5,6)

which generates this error:

TypeError: 'tuple' object does not support item assignment

While this code:

tup = ([1,2,3],[7,8,9])
try:
    tup[0] += (4,5,6)
except TypeError:
    print tup

prints this:

([1, 2, 3, 4, 5, 6], [7, 8, 9])

Is this behavior expected?

Note

I realize this is not a very common use case. However, while the error is expected, I did not expect the list change.

解决方案

Yes it's expected.

A tuple cannot be changed. A tuple, like a list, is a structure that points to other objects. It doesn't care about what those objects are. They could be strings, numbers, tuples, lists, or other objects.

So doing anything to one of the objects contained in the tuple, including appending to that object if it's a list, isn't relevant to the semantics of the tuple.

(Imagine if you wrote a class that had methods on it that cause its internal state to change. You wouldn't expect it to be impossible to call those methods on an object based on where it's stored).

Or another example:

>>> l1 = [1, 2, 3]
>>> l2 = [4, 5, 6]
>>> t = (l1, l2)
>>> l3 = [l1, l2]
>>> l3[1].append(7)

Two mutable lists referenced by a list and by a tuple. Should I be able to do the last line (answer: yes). If you think the answer's no, why not? Should t change the semantics of l3 (answer: no).

If you want an immutable object of sequential structures, it should be tuples all the way down.

Why does it error?

This example uses the infix operator:

Many operations have an "in-place" version. The following functions provide a more primitive access to in-place operators than the usual syntax does; for example, the statement x += y is equivalent to x = operator.iadd(x, y). Another way to put it is to say that z = operator.iadd(x, y) is equivalent to the compound statement z = x; z += y.

https://docs.python.org/2/library/operator.html

So this:

l = [1, 2, 3]
tup = (l,)
tup[0] += (4,5,6)

is equivalent to this:

l = [1, 2, 3]
tup = (l,)
x = tup[0]
x = x.__iadd__([4, 5, 6]) # like extend, but returns x instead of None
tup[0] = x

The __iadd__ line succeeds, and modifies the first list. So the list has been changed. The __iadd__ call returns the mutated list.

The second line tries to assign the list back to the tuple, and this fails.

So, at the end of the program, the list has been extended but the second part of the += operation failed. For the specifics, see this question.

这篇关于附加到元组中定义的列表 - 这是一个错误吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆