在Python中,+=运算符返回的是两个操作数相加后的值。
在Python中,+=运算符返回的是两个操作数相加后的值。
当我试图回答stackoverflow上关于Python中“=”和“+=”的区别的另一个人的问题时,我遇到了以下问题:\n
class Foo: def __init__(self, value, name="default"): self.value = value self.name = name def __add__(self, that): return Foo(self.value + that.value) def __iadd__(self, that): self.value = self.value + that.value return self def __str__(self): return "name: {}, value: {:d}".format(self.name, self.value) a = Foo(1, 'alice') b = Foo(2, 'bob') print(a+=b)
\n最后的`print`调用不成功,并给出以下错误:\n
File "", line 3 print(a+=b) ^ SyntaxError: invalid syntax
\n我不知道为什么这个不起作用。也许与关键字参数传递机制有关?我只是找不到关于这个主题的任何资源,因为重载的`__iadd__`方法已经返回一个`Foo`对象。\n************** 更新 ******************\n如果我像这样修改`__iadd__`方法(只移除`return`语句):\n
... def __iadd__(self, that): print("__iadd__ was called") self.value = self.value + that.value a = Foo(1, 'alice') b = Foo(2, 'bob') a += b print(a) # 输出:None
\n所以,`__iadd__`中的最后一个`return`语句确实是必需的。但它不像我想的那样起作用(我来自C/C++背景,所以这种行为对我来说有点奇怪)\n************************* 第二次更新 ********************************\n我几乎忘记了在Python中,`=`构成了一个语句而不是一个表达式。`__iadd__`中的`return`语句和我在其他语言中的经验使我产生了一种错觉,即`+=`可以用作表达式。\n如Python文档所述,`__add__`用于构造一个新对象。`__iadd__`用于原地修改。但这完全取决于实现。尽管`__iadd__`返回一个对象,但该对象在某种程度上被语言“拦截”并重新分配给左操作数,最终效果是,`__iadd__`仍然是一个语句,而不是一个表达式。如果我理解错了,请纠正我。此外,我没有找到任何证实`+=`是一个语句的资源。\n
总结
\n
- \n
- 一个简单的代码,比如`a = 1`是一个赋值语句。它不能用作函数参数。但是,关键字参数传递没有受到此限制:`print(\'Hello world\', end=\'\')`仍然有效。
- \n
- \n
- `x = x + y`等同于`x = x.__add__(y)`,
- `x += y`等同于`x = x.__iadd__(y)`,详细信息请查看文档。
\n
\n
\n
- 一个例子:
\n
\n
\n
\n
class Foo: def __init__(self, value, name="default"): self.value = value self.name = name def __add__(self, that): return Foo(self.value + that.value) def __iadd__(self, that): self.value = self.value + that.value return self def __str__(self): return "name: {}, value: {:d}".format(self.name, self.value) a = Foo(1, 'alice') b = Foo(2, 'bob') c = a + b # 对象a和b不变 a += b # 对象a被修改 print(c) # 输出:name: default, value: 3 print(a) # 输出:name: alice, value: 3
这是一个语法错误,是因为将赋值语句用作表达式。这里有另一个Stack Overflow的帖子,解释了语句和表达式之间的差异。
这不是运算符重载实现的错误。
在另一个上下文中,这个语法错误的示例(使用int而不是Foo):
a = 2 b = 3 # 仍然是个错误! print(a += b) # 使用标准int += 运算符时出错
如何修复语法问题:
a = 2 b = 3 a += b # 将赋值语句分开... print(a) # ...并给print函数一个表达式
这与运算符有关。运算符使这行成为一个语句(即“不可打印的”)。
感谢指出我的措辞不明确。我更新了我的帖子,澄清了这个错误不是源自实现,而是源自它的使用方式。
Python中的运算符+=返回的是什么?这个问题的出现是因为Python的语义可能会让事情变得混乱。为了举例说明,可以尝试通过以下示例进行演示:
class Foo: def __init__(self, value): self.value = value def __iadd__(self, other): self.value = self.value + other.value return 'did iadd' a = Foo(1) c = a c += Foo(2) print((c, a.value))
应该得到打印出`('did iadd', 3)`。
根据文档:
x += y 相当于 x = x.__iadd__(y)
`__iadd__`的约定是你应该以这样的方式实现它,使得`x = x + y`的语义与`x += y`的语义“相同”。"相同"取决于问题的细节,例如对于不可变对象(例如整数或字符串),这将需要分配一个新对象并更新引用以指向新对象,例如:
a = 500 # move out of the "interned" number space c = a a += 1 print(id(a), id(c))
应该给出两个不同的数字,在CPython中它们将是两个不同的地址,都是独立且不可变的int对象。对于其他数据类型,允许进行可变/原地更新可能是有用的,例如为了提高效率或其他原因。`__iadd__`的语义允许类的实现选择一个默认值。
每种语言都有其独特之处,因此建议不要试图与C++进行太直接的比较。特别是因为C++有很多历史包袱被迫携带。
的确,`x += y`与`x = x.__iadd__(y)`是相同的。最“流行”的答案表明`x += y`与`x = x + y`相同是令人困惑的,因为`x += y`调用`__iadd__`而`x = x + y`调用`__add__`,两者都跟随一个赋值操作。我现在认为这一点非常清楚了。谢谢!
在Python中,运算符+=用于将右侧的值添加到左侧的变量,并将结果赋给左侧的变量。然而,这个操作符返回的值与其他语言中的操作符不同。在Python中,+=操作符返回的是被赋值后的变量的引用,并不是赋值的结果。
这种设计是有原因的。其中一个原因是为了避免类似于C语言中的经典错误。在C语言中,如果将赋值操作符"="误写成"==",就会导致条件判断出错。例如,如果写成if (a=b),实际上用户可能想要测试的是a==b,但实际上会将b赋给a。为了避免这种常见的错误,Python中的赋值操作符不返回赋值的结果。
然而,Python 3.8引入了一种新的赋值方法,称为赋值表达式。赋值表达式允许将赋值的结果作为参数传递,这在列表推导中非常方便。虽然不能直接进行原地相加的操作,但可以先进行相加,然后再赋值。
例如,在Python 3.8中,可以这样使用赋值表达式:
a = 2
b = 3
print(a := a + b)
输出结果为5。在这个例子中,a先与b相加得到结果5,然后将结果赋给a,并将结果打印出来。
总结起来,Python中的+=操作符返回的是被赋值后的变量的引用,并不是赋值的结果。这种设计是为了避免常见的赋值错误。然而,Python 3.8引入了赋值表达式,可以方便地将赋值的结果作为参数传递。虽然不能直接进行原地相加的操作,但可以先进行相加,然后再赋值。这种新的赋值方法为Python的使用带来了更多的灵活性和便利性。