15

我遇到了关于 python 增强分配的一些有趣的事情+=

a += b如果 a 是“更简单”的数据类型,似乎并不总是自动进行数据类型转换,而a = a + b似乎总是有效

转换完成的情况

a = 1
b = 1j

a = 1
b = 0.5

未完成转换的情况

from numpy import array
a = array([0, 0 ,0])
b = array([0, 0, 1j])

之后a += ba保持为整数矩阵,而不是复矩阵

我以前认为a += b是一样的a = a + b,它们在底层实现上有什么区别?

4

4 回答 4

16

对于+运算符,Python 定义了对象可以实现的三个“特殊”方法:

  • __add__:添加两个项目(+运算符)。当你这样做a + b时,__add__方法作为参数a被调用。b
  • __radd__:反映添加;对于a + b, 的__radd__方法作为实例b被调用。a这仅在a不知道如何添加并且两个对象是不同类型时使用。
  • __iadd__:就地添加;用于a += b将结果分配回左侧变量的位置。这是单独提供的,因为它可能以更有效的方式实现。例如,如果a是一个列表,则a += b与 相同a.extend(b)。但是,如果您必须在扩展它之前c = a + b制作副本,因为在这种情况下不会被修改。请注意,如果您不实现,那么 Python 只会调用。aa__iadd____add__

因此,由于这些不同的操作是用不同的方法实现的,因此有可能(但通常是不好的做法)实现它们,以便它们做完全不同的事情,或者在这种情况下,可能只是略有不同的事情。

其他人推断您正在使用 NumPy 并解释了它的行为。但是,您询问了底层实现。希望您现在明白为什么有时情况a += ba = a + b. 顺便说一下,也可以为其他操作实现类似的三种方法。有关所有受支持的就地方法的列表,请参阅此页面。

于 2010-12-07T23:04:19.057 回答
8

如果arraynumpy.array(您实际上没有指定),那么发生的问题是因为这些数组无法更改它们的类型。当您创建没有类型说明符的数组时,它会猜测类型。如果您然后尝试执行类型不支持的操作(例如将其添加到具有更大域的类型,例如 complex),numpy 知道执行计算,但它也知道结果只能存储在类型中具有更大的域。它抱怨(在我的机器上,无论如何,我第一次做这样的任务)结果不合适。当您进行常规添加时,无论如何都必须创建一个新数组,并且 numpy 会为其提供正确的类型。

>>> a=numpy.array([1])
>>> a.dtype
dtype('int32')
>>> b=numpy.array([1+1j])
>>> b.dtype
dtype('complex128')
>>> a+b
array([ 2.+1.j])
>>> (a+b).dtype
dtype('complex128')
>>> a+=b
>>> a
array([2])
>>> a.dtype
dtype('int32')
>>> 
于 2010-12-07T22:57:46.700 回答
1

a = a + b和之间的区别在于a += b,后一种添加将尽可能“就地”完成,这意味着通过更改对象a。您可以通过列表轻松查看这一点。

a = b = [1, 2]
a += [3]
print b # [1, 2, 3]
a = b = [1, 2]
a = a + [3]
print b # [1, 2]
于 2010-12-07T22:53:29.290 回答
0

Rafe Kettler 的回答是正确的,但似乎您在将 a=[0,0,0] 添加到 b 后设法得到了(根据您的帖子)。

好吧,如果您使用的是 numpy 或 scipy(我之所以这么说是因为我看到array并想知道这里正在创建什么数组),那么这是“正常的”,甚至应该发出警告:

ComplexWarning:将复数转换为实数会丢弃虚部

于 2010-12-07T22:49:51.197 回答