python函数调用后变量的意外更改

时间:2019-05-19 02:55:34

标签: python pass-by-reference

考虑下面的小python代码段,在其中将“ 2”添加到3 x 3矩阵的第一列:

import numpy as np

def changeValue(kernel):
    kernel[0,0]=kernel[0,0]+ 2 
    kernel[1,0]=kernel[1,0]+ 2 
    kernel[2,0]=kernel[2,0]+ 2 
    return kernel

myKernel = np.array((
 [0, -1, 0],
 [-1, 5, -1],
 [0, -1, 0]), dtype="int")
CVkernel=myKernel

print(CVkernel)
a=changeValue(myKernel)
print(a)
print(CVkernel)

我得到以下输出

[[ 0 -1  0]
 [-1  5 -1]
 [ 0 -1  0]]

[[ 2 -1  0]
 [ 1  5 -1]
 [ 2 -1  0]]

[[ 2 -1  0]
 [ 1  5 -1]
 [ 2 -1  0]]

myKernel副本CVkernel的值。我认为发生了意外的按引用调用(按引用传递?),但是我不确定为什么。

如果我对函数的定义稍有不同

def changeValue2(kernel):
    kernel=kernel + 2 
    return kernel

然后保持CVkernel不变

[[ 0 -1  0]
 [-1  5 -1]
 [ 0 -1  0]]

[[2 1 2]
 [1 7 1]
 [2 1 2]]

[[ 0 -1  0]
 [-1  5 -1]
 [ 0 -1  0]]

这是怎么回事?我尝试使用print(id(kernel))和print(id(CVkernel))打印出变量的地址寄存器,但这并没有说明。

编辑 即使当我使用“安全”函数调用kernel = kernel + 2时,myKernel和CVkernel的ID也相同。

id of myKernel  139994865303344
myKernel 
[[ 0 -1  0]
 [-1  5 -1]
 [ 0 -1  0]]
id of CVKernel  139994865303344
CVKernel 
[[ 0 -1  0]
 [-1  5 -1]
 [ 0 -1  0]]

**call made to changeValue2**

id of myKernel  139994865303344
myKernel 
[[ 0 -1  0]
 [-1  5 -1]
 [ 0 -1  0]]
id of CVKernel  139994865303344
CVKernel 
[[ 0 -1  0]
 [-1  5 -1]
 [ 0 -1  0]]
output a 
[[2 1 2]
 [1 7 1]
 [2 1 2]]

如果每个变量的ID是不同的实例,它们的ID是否应该不同?

3 个答案:

答案 0 :(得分:1)

尝试如下操作:

def changeValue2(kernel):
    kernel += 2 
    return kernel

结果显示如下:

[[ 0 -1  0]
 [-1  5 -1]
 [ 0 -1  0]]
[[2 1 2]
 [1 7 1]
 [2 1 2]]
[[2 1 2]
 [1 7 1]
 [2 1 2]]

您很清楚它是a call by reference,但是,在kernel = kernel + 2的情况下,左边的kernel成为另一个实例。简单来说,它与newKernel = kernel + 2相同。

因此,我将其更改为kernel += 2,并修改了原始kernel实例。

答案 1 :(得分:1)

  

原因

永远不要直接修改对象内核  您传递给函数changeValue2

请检查此链接 How arguments passed in python找出尝试修改参数时真正发生的事情

  

解决方案:

  1. 只需使用changeValue

  2. 使用返回值:myKernel = changeValue2(myKernel)

  3. 只需复制yaho cho的解决方案,再次感谢:)

def changeValue2(kernel):
    kernel += 2 
    return kernel

答案 2 :(得分:-1)

我建议:

    CVkernel=myKernel.copy()