Python赋值运算符与非赋值不同

Posted

技术标签:

【中文标题】Python赋值运算符与非赋值不同【英文标题】:Python assignment operator differs from non assignment 【发布时间】:2020-08-10 21:42:10 【问题描述】:

我遇到了这种奇怪的行为,我找不到解释。

MWE:

l = [1]
l += 'a': 2
l
[1, 'a']
l + 'B': 3
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: can only concatenate list (not "dict") to list

基本上,当我+= python 不会引发错误并将键附加到列表中时,当我只计算+ 时,我会得到预期的TypeError

注意:这是 Python 3.6.10

【问题讨论】:

查看https://***.com/questions/15376509/when-is-i-x-different-from-i-i-x-in-python 见bugs.python.org/issue9314 - “用迭代器连接列表时结果不一致”。另请注意,+= 等在 PEP 中被称为“增强分配”,PEP 203。 这有点奇怪 我认为@alkasm 的错误链接有一个很好的解释。 When a is mutable, a += b updates it in-place, so there is no ambiguity: the type of a cannot change. When you do a + b, there is no reason to treat a as more deserving than b when selecting the type of the result. @ChrisDoyle 这就是确切的推理。这不是“错误”,它是一种防止解释器猜测的机制。 【参考方案1】:

l += ...实际上是在调用object.__iadd__(self, other)并在l可变时修改对象in-place

原因(正如@DeepSpace 在他的评论中解释的那样)是,当您执行 l += 'a': 2 时,操作仅在原地更新 l 并且仅当 l 是可变的时。另一方面,l + 'a': 2 操作未在适当位置完成,导致list + dictionary -&gt; TypeError


(见here)


l = [1]
l = l.__iadd__('a': 2)
l
#[1, 'a']

与调用object.__add__(self, other)+不同

l + 'B': 3
TypeError: can only concatenate list (not "dict") to list

【讨论】:

这也应该说明原因了。 l += ... 更新 l 就地,所以结果的类型是明确的(= l 的类型)。 l + ... 是模棱两可的,因为它没有到位,所以生成的新对象的类型不清楚(应该是l 的类型还是应该是... 的类型?) 当然!我将此添加到我的答案中。 l += ...就地运行 @seralouk,您介意分享您使用哪个工具来找出调用了哪个函数吗?检查、pdb 等? 文档:docs.python.org/3/reference/datamodel.html#object.__iadd__ 和一些编程知识,例如字典是可变的。 @DeepSpace 的推理是有道理的,但 __iadd__ 不能保证返回相同的对象。见number += 2。另外,来自文档:这些方法应该尝试就地执行操作(修改自我)并返回结果(可能是但不一定是自我)【参考方案2】:

正如作者所说,这不是错误。当你做a += b 时,就像b 来到a 的家,并以a 喜欢的方式改变它。 作者所说的是,当您执行a + b 时,无法确定哪种风格会被优先考虑。在你执行之前,没有人知道a + b 的结果会去哪里。所以你无法决定它的风格。如果是a 样式,则为[1, 'a'] 的样式,如果为b 样式,则为错误。因此无法决定谁将获得优先权。所以我个人不同意这种说法。因为当您使用调用堆栈时,a 的位置比b 高。当有像a + b 这样的表达式时,如果a.__add__NotImplemented(在这种情况下已实现),则首先调用a.__add__(self, other)。然后你打电话给a.__radd__(self, other)。这意味着在这种情况下调用other.__add__ b.__add__。我是根据调用堆栈的位置来说明这一点的,python 社区可能有更重要的理由这样做。

【讨论】:

以上是关于Python赋值运算符与非赋值不同的主要内容,如果未能解决你的问题,请参考以下文章

Python中在进行赋值运算时即使两侧操作数的类型不同也不会报错?

Python新手学习基础之运算符——赋值与逻辑运算

Python赋值运算符

深入解析Python中的变量和赋值运算符

深入解析Python中的变量和赋值运算符

复制构造函数与赋值运算符(=)有何不同