Python函数调用后NumPy数组变量意外变更的原因探究
你遇到的其实是Python中可变对象(比如NumPy数组)的引用赋值和函数传参特性,咱们一步步拆解清楚:
1. 为什么CVkernel会跟着myKernel一起变?
当你执行CVkernel=myKernel时,并没有创建新的NumPy数组——这只是把CVkernel这个变量名绑定到了和myKernel完全相同的内存对象上。换句话说,两个变量指向的是同一个数组实例,就像给同一个房间装了两扇门。
在changeValue函数里,你做的是原地修改数组元素:
kernel[0,0]=kernel[0,0]+ 2
这种操作直接修改了数组对象本身的内容,而不是生成新对象。所以不管是通过myKernel、CVkernel还是函数里的kernel参数访问,都是同一个数组,自然修改后所有变量的输出都会同步变化。
2. 为什么changeValue2里CVkernel不受影响?
在changeValue2函数中,kernel=kernel + 2这行代码分两步执行:
- 首先
kernel + 2会创建一个全新的NumPy数组(原数组每个元素加2后的独立副本) - 然后把函数内部的局部变量
kernel,重新绑定到这个新创建的数组上
但要注意:这个操作只改变了函数内部局部变量的指向,外部的myKernel和CVkernel仍然牢牢绑定在原来的数组对象上。所以函数执行完后,外部的CVkernel还是原来的内容,而函数返回的只是那个新生成的数组。
3. 为什么myKernel和CVkernel的id始终相同?
因为从CVkernel=myKernel执行的那一刻起,两个变量就指向了同一个对象——id是Python对象的唯一标识,同一个对象的id肯定完全一致。
在changeValue2函数里,虽然内部的kernel变量在赋值后会指向新对象(此时函数内部的kernelid会变化),但这完全不影响外部的myKernel和CVkernel的绑定关系,它们依然指向最初的那个数组,所以id自然始终不变。
快速解决:创建独立副本
如果想让CVkernel成为myKernel的独立副本,互不影响,可以用NumPy的copy()方法:
CVkernel = myKernel.copy()
这样后续不管怎么修改myKernel,CVkernel都不会跟着变了。
内容的提问来源于stack exchange,提问作者aquagremlin

