【问题标题】:Why does += of a list within a Python tuple raise TypeError but modify the list anyway? [duplicate]为什么 Python 元组中列表的 += 会引发 TypeError 但仍要修改列表? [复制]
【发布时间】:2012-05-10 22:42:05
【问题描述】:

我刚刚遇到了一件很奇怪的事情。

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

为什么它会引发TypeError,却改变tuple 中的list

【问题讨论】:

  • 我想你得看看+= 是如何实现的。似乎它实际上并没有创建一个新列表,它就地更改了列表,这就是 + 部分。然后你就有了分配,但是由于元组是不可变的,所以这是不允许的。
  • @FelixKling += 的作用类似于 append(),即列表的 id() 保持不变。
  • 还要注意,为了能够散列一个元组,它的所有组成部分也必须是可散列的。
  • 这是在the official FAQ,有一个很好的解释。还有一个 bug report 解释了为什么它不是错误。

标签: python


【解决方案1】:

【讨论】:

    【解决方案2】:

    正如我在评论中开始提到的,+= 实际上修改了列表就地,然后尝试将结果分配给元组中的第一个位置。来自data model documentation

    调用这些方法来实现增强的算术赋值(+=、-=、=、/=、//=、%=、*=、>=、 &=、^=、|=)。这些方法应该尝试就地执行操作(修改 self)并返回结果(可以是但不一定是 self)。

    += 因此等价于:

    t[0].extend(['world']);
    t[0] = t[0];
    

    因此就地修改列表不是问题(1. 步骤),因为列表是可变的,但是将结果分配回元组是无效的(2. 步骤),这就是引发错误的地方。

    【讨论】:

    • 为了澄清一下,现有列表确实与来自 RHS 的列表连接在一起,但是对元组的分配失败,但它对列表对象的引用仍然保持不变。这就是为什么您会看到列表更新并且元组引发了 TypeError
    • 知道了。现在说得通了。谢谢。
    • @Felix Kling 但即使在 += 之后列表的 id() 保持不变,但是如果我们这样修改列表的 id() 会发生变化,例如 x[0]=x [0]+['list'] ,其中 x 是列表的列表。
    • @Ashwini:只有+= 应该修改列表就地(没有新列表)。如果您有普通的+ 运算符,则实现很可能会返回该类的新实例(新列表)。试试x[0] += ['list']。或者你的观点是什么?我不确定我是否理解。
    • +1 @FelixKling 我明白你的意思。
    猜你喜欢
    • 2020-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-16
    • 2010-10-19
    • 1970-01-01
    相关资源
    最近更新 更多