неожиданное изменение переменной после вызова функции python - PullRequest
2 голосов
/ 19 мая 2019

Рассмотрим следующий небольшой фрагмент кода 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)), и это не проливает свет.

EDIT Даже когда я используювызов функции safe, kernel = kernel + 2, идентификаторы myKernel и CVkernel совпадают.

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

Разве идентификатор каждой переменной не должен быть разным, если это разные экземпляры?

Ответы [ 3 ]

1 голос
/ 19 мая 2019

Попробуйте, как показано ниже:

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 голос
/ 19 мая 2019

Причина

Вы никогда не должны напрямую изменять объект ядро ​​, которое вы передали функции changeValue2.

, пожалуйста, проверьте эту ссылку Как аргументы передаются в python , чтобы узнать, что на самом деле произошло, когда вы пытаетесь изменить параметр

Решение:

  1. простоиспользуйте changeValue

  2. используйте возвращаемое значение: myKernel = changeValue2(myKernel)

  3. Просто копию yaho cho solusion, еще раз спасибо:)

def changeValue2(kernel):
    kernel += 2 
    return kernel
0 голосов
/ 19 мая 2019

Я предлагаю:

    CVkernel=myKernel.copy()
...