此示例摘自15:30的this视频:

x = 1, [2], 3
x[1] += [20]


由于某种原因,它发出一个TypeError(“ tuple”对象不支持项目分配),但是成功了,所以现在

print(x)  # (1, [2, 20], 3)


即如果您在repl中执行上述操作,那么它就可以正常工作。要在脚本中看到相同的效果,请使用

x = 1, [2], 3
try:
    x[1] += [20]
except TypeError as e:
    print(e)
print(x)


如何解释这种行为?好像列表对象本身首先被突变(成功),然后尝试将该列表重新分配给“名称” x[1]的尝试,然后引发异常。但是,为什么Python会在可变类型上尝试+=的(冗余)重新分配?

最佳答案

其实你是对的。这正是python所做的。

+=运算符仅使用魔术方法__iadd__。所以这段代码:

a_list = []
a_list += [1]


等效于:

a_list = []
a_list = a_list.__iadd__([1])


__iadd__方法通常会修改对象并返回它,以便此分配有效,这就是代码中所发生的事情。您的代码等效于:

x = 1, [2], 3
try:
    x[1] = x[1].__iadd__([20])
except TypeError as e:
    print(e)
print(x)


希望现在您能看到问题所在。 __iadd__调用按预期方式工作并修改了列表,但是随后您尝试将其重新分配给不允许的元组的第二个元素。

至于为什么要这样实现:您是否注意到我在上面强调了“通常”这个词。当您在自己的类中实现此方法时,不必返回您使用的同一对象。您可以退还其他东西。这就是为什么必须重新分配的原因。为什么要这样做是一个不同的问题,但是在python中,如果您尝试尝试,几乎可以破坏所有内容。

您的问题实际上在python FAQ中。我建议您阅读它,并阅读有关augmented assignments的更多信息。

10-04 10:58
查看更多