Python/Numpy函数修改并返回输入变量时的异常行为疑问
这是Python/Numpy的预期行为还是Bug?
我写了一段测试脚本,其中函数的输入和输出用了同一个变量,示例代码如下:
import numpy as np def sign(x: np.ndarray): # Return x/abs(x) nz_idx = np.abs(x)!= 0 x[nz_idx] = x[nz_idx] / np.abs(x[nz_idx]) return x if __name__ == "__main__": x = np.zeros((10,1), dtype=float) x[:, 0] = np.arange(1,11) print(x) y = sign(x) print(x)
我原本预期的输出是:
[0. 1. 2. 3. 4. 5. 6. 7. 8. 9.]
[0. 1. 2. 3. 4. 5. 6. 7. 8. 9.]
因为我认为函数不应该修改输入变量x,但实际得到的输出是:
[0. 1. 2. 3. 4. 5. 6. 7. 8. 9.]
[0. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
这明显不符合预期,后来我在sign函数里新增变量并使用copy()方法修复后,得到了正确输出:
def sign(x: np.ndarray): z = x.copy() nz_idx = np.abs(z)!= 0 z[nz_idx] = z[nz_idx] / np.abs(z[nz_idx]) return z
请问这是Python/Numpy的预期行为还是一个bug?
解答
这是完全符合预期的行为,不是bug。
原因在于:Numpy数组属于Python中的可变对象,当你把一个可变对象作为参数传入函数时,函数接收的是这个对象的引用,而不是它的副本。在函数内部直接对这个引用指向的对象进行原地修改(比如x[nz_idx] = ...这种赋值操作),会直接改变原对象的内容,外部的变量x自然也会看到修改后的结果。
你用x.copy()创建原数组的副本,再对副本进行修改并返回,这种做法是正确的——这样既不会影响原输入数组,也能得到你需要的计算结果。如果不想手动处理拷贝,也可以考虑使用Numpy自带的np.sign函数,它会返回一个新数组,不会修改原输入。
内容的提问来源于stack exchange,提问作者Karthik Upadhya
相关产品推荐
相关产品推荐

