x += y 和 x = x + y 的区别

The difference between x += y and x = x + y

我有这个python代码

x = [1, 2, 3]
y = x
x += [4]
>>> print(y)
[1, 2, 3, 4]

所以,这是因为 x is yTrue,如果我更改 x,我会更改 y

但是当我这样做时:

x = [1, 2, 3]
y = x
x = x + [4]
>>> print(y)
[1, 2, 3]

>>> id(x) == id(y)
False

我想知道有什么区别。我以为 x += 1 是 shorthand for x = x+1 但显然肯定有区别。

我更困惑了,当我尝试上面的字符串时:

name = 'John'
name_2 = name
name += ' Doe'

>>> print(name_2)
'John'

所以我认为+=的效果取决于左边的对象,是否可变?

“左边”的对象处理运算符(通常,参见 r-运算符形式);在这种情况下,它是 Inplace Operator.

10.3.2. Inplace Operators

Many operations have an “in-place” version. Listed below are functions providing 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) ..

实际结果由“x”对象决定,如果它处理__iadd__(例如,像列表一样突变)或只是__add__ (例如,一个新的结果对象,与字符串一样)——选择使用哪个协议,以及分配给 return 的什么值,由 operator.iadd 本身 1[ 决定=37=].

因此 x += y ~~ x = x + y 的 shorthand 对于某些对象 为真 - 特别是那些不可变且 [仅] 实现 __add__ 的对象.

How are Python in-place operator functions different than the standard operator functions?


1 从语义上讲,operator.iadd 函数的工作原理类似于:

if x.__iadd__:
    x.__iadd__(y)        # side-effect performed on x,
    return x             # returns original-but-modified object
else
    return x.__add__(y)  # return new object,
                         # __add__ should not have side-effects

如@BrenBarn 所说,如果左侧对象是可变的,它将执行就地操作。否则将返回一个新副本,并且因为它已被复制,所以它们的 id 将不再匹配。

在后台,它的运行类似于此:

>>> import copy
>>> y = [1,2,3]
>>> x = y
>>> x+=[4]
>>> y
[1, 2, 3, 4]
>>> x = copy.copy(y) #perhaps even a deepcopy()? Don't know.
>>> y
[1, 2, 3, 4]
>>> x
[1, 2, 3, 4]
>>> x += [5]
>>> y
[1, 2, 3, 4]
>>> x
[1, 2, 3, 4, 5]

编辑 1:

class test():
    def __init__(self, ll):
        self.a = ll
    def __add__(self, other):
        return test(ll=self.a+other.a)

>>> a = test([[1,2],[3,4]])
>>> a.a
[[1, 2], [3, 4]]
>>> x = test([[1,2],[3,4]])
>>> x += a
>>> x.a
[[1, 2], [3, 4], [1, 2], [3, 4]]
>>> a.a
[[1, 2], [3, 4]]
>>> x.a[2][0] = 7
>>> x.a
[[1, 2], [3, 4], [7, 2], [3, 4]]
>>> a.a
[[7, 2], [3, 4]]