Numpy函数中A *= B与A = A*B的行为差异及原因咨询
关于NumPy中
A = A * B与A *= B行为差异的疑问 以下两段NumPy代码会产生不同的行为:
代码1:使用A = A * B
import numpy as np def func1(A, B): A = A * B return A A = np.arange(3, dtype=float) B = np.full(3, 2.0) C1 = func1(A, B) print(" func 1", C1) print(" A after function 1 = ", A) print()
运行结果:
C1 = [0.0, 2.0, 4.0](符合预期)- 原数组
A未改变,仍为[0.0, 1.0, 2.0]
代码2:使用A *= B
def func2(A, B): A *= B return A A = np.arange(3, dtype=float) B = np.full(3, 2.0) C2 = func2(A, B) print(" func 2", C2) print(" A after function 2 = ", A)
运行结果:
C2 = [0.0, 2.0, 4.0](符合预期)- 原数组
A被修改为[0.0, 2.0, 4.0]
疑问
原本以为func2内的数组A在运算时会自动复制,这种行为差异十分危险,想咨询为何会出现这种情况?两者的行为难道不应该一致吗?
解答
这两种操作的本质完全不同:
A = A * B:创建新数组A * B会计算两个数组的元素乘积,生成一个全新的NumPy数组,之后函数内部的变量A会被重新赋值为这个新数组的引用。此时函数内的A和外部的原数组A已经指向不同的内存空间,所以外部数组不会被修改。A *= B:原地修改操作
这个复合赋值运算符对应NumPy数组的__imul__方法,它不会创建新数组,而是直接在原数组的内存空间上完成计算并修改数据。因为函数内部的A是外部数组的引用,所以原地修改会直接影响到外部的原数组。
NumPy设计原地操作的初衷是节省内存(尤其是处理超大数组时),但如果忽略这个特性确实会意外修改原数据。如果需要避免修改原数组,要么使用A = A * B这种生成新数组的方式,要么先手动复制数组再操作,比如:
def func2_safe(A, B): A_copy = A.copy() A_copy *= B return A_copy
内容的提问来源于stack exchange,提问作者Ong Beng Seong
相关产品推荐
相关产品推荐

