Numpy 为什么把a+=b和a=a+b视为不同的操作
在使用Numpy时,我们会遇到一个问题:为什么Numpy把a+=b和a=a+b视为不同的操作?在本文中,我们将深入研究这个问题,并通过示例说明。
阅读更多:Numpy 教程
等式操作的区别
在Numpy中,如果我们执行以下操作:
import numpy as np
a = np.zeros((3,3))
b = np.ones((3,3))
a += b
则a的值将变成一个3×3数组,其值均为1。
然而,如果我们执行以下操作:
import numpy as np
a = np.zeros((3,3))
b = np.ones((3,3))
a = a + b
则a的值将变成一个3×3数组,其值均为1,但这个调用会返回一个不同的数组。
这种行为的原因是,Numpy在执行上述操作时,在内部会创建一个临时数组,用于保存a+b的结果,并在内部计算中使用该临时数组。然后,将a中的值更新为临时数组中的值。这种行为可能会影响性能,因此,Numpy要求在执行类似于a=a+b的操作时,创建一个新的数组,并将其分配给a,而不是在内部使用临时数组。
这里有一个示例,在这个示例中,我们定义了两个 10000×10000 的数组A和B,并计算它们的和。在使用+=操作符时,Numpy几乎可以立即返回结果,但是,使用=操作符时,Numpy则需要显示地创建和分配一个新的数组,并将B的值复制到该数组中。
import numpy as np
import time
# 使用+=进行计算
a = np.zeros((10000,10000))
b = np.ones((10000,10000))
t1 = time.time()
a += b
t2 = time.time()
print("Using += operator: "+str(t2-t1)+" seconds")
# 使用=进行计算
a = np.zeros((10000,10000))
b = np.ones((10000,10000))
t1 = time.time()
a = a + b
t2 = time.time()
print("Using = operator: "+str(t2-t1)+" seconds")
赋值问题
当然,这种行为也会导致其他问题。例如,在Numpy中,如果我们使用=操作符进行赋值,则赋值的是这个对象的一个新副本,而不是地址。这意味着,如果我们更改a,则不会更改b,如下所示:
import numpy as np
a = np.zeros((3,3))
b = a
a += np.ones((3,3))
print(a)
print(b)
这段代码的输出是:
array([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]])
array([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]])
然而,如果我们使用=进行赋值操作,则无论更改a还是b都会更改另一个变量的值,如下所示:
import numpy as np
a = np.zeros((3,3))
b = a
a = np.ones((3,3))
print(a)
print(b)
这段代码的输出是:
array([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]])
array([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]])
可变对象的问题
注意,在Numpy中,不可变对象的行为是不同的。例如,如果我们执行以下操作:
a = 1
b = a
a += 1
print(a)
print(b)
这段代码的输出是:
2
1
这是因为在Python中,整数是不可变对象,因此a += 1的结果是创建一个新的整数对象,而不是在原始对象上进行操作。
总结
Numpy在处理a+=b和a=a+b时有所不同,是因为后者需要显示地创建和分配一个新的数组,并将B的值复制到该数组中,可能会影响性能。另外,在Numpy中,使用=进行赋值的行为与Python中不可变对象的行为相同,但在可变对象中则不同。