aquagremlin
aquagremlin

Reputation: 3549

unexpected change in variable after python function call

Consider the following small python snippet where I add '2' to the first column of a 3 x 3 matrix:

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)

I get the following output

[[ 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]]

The value of myKernel clobbers CVkernel. I think there is an unintentional call-by-reference (pass-by-reference?) going on but I am not sure why.

If I define the function slightly differently

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

Then CVkernel is left untouched

[[ 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]]

What is going on here? I tried printing out the address register of the variables with print(id(kernel)) and print(id(CVkernel)) and that does not shed any light.

EDIT Even when I use a 'safe' function call, kernel=kernel + 2 , the id of myKernel and CVkernel are the same.

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]]

Shouldn't the id of each variable be different if they are different instances?

Upvotes: 2

Views: 302

Answers (3)

imanux
imanux

Reputation: 11

Reason

You should never directly modify the object kernel you passed to the function changeValue2.

please check this link How arguments passed in python to find out what really happened when you try to modify the param

Solution:

  1. just use changeValue

  2. use the return value: myKernel = changeValue2(myKernel)

  3. Just a copy of yaho cho's solusion, Thanks again :)

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

Upvotes: 1

yaho cho
yaho cho

Reputation: 1779

Try it as below:

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

It shows the result as below:

[[ 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]]

You know well that It's a call by reference, but, In case of kernel = kernel + 2, the left kernel becomes another instance. Simply, It is same as newKernel = kernel + 2.

So, I changed it to kernel += 2, and it modified original kernel instance.

Upvotes: 1

Fan Jups
Fan Jups

Reputation: 14

I suggest :

    CVkernel=myKernel.copy()

Upvotes: -1

Related Questions