有什么不同? numpy.array 绕过 ref

What is the difference? numpy.array pass by ref

为什么我们在这些 np.array 上有两种不同的行为?

    def pass_by_ref(A: np.array):
        A = np.ones((2,2))
        return A

    def pass_by_ref_sideEffect(A: np.array):
        A[0][0] = 2
        return A


    A = np.zeros((2,2))

    B = pass_by_ref(A)
    print("A =\n", A)
    print("B =\n", B)

    C = pass_by_ref_sideEffect(A)
    print("A =\n", A)
    print("C =\n", C)

输出:

    A =
     [[0. 0.]
     [0. 0.]]
    B =
     [[1. 1.]
     [1. 1.]]
    A =
     [[2. 0.]
     [0. 0.]]
    C =
     [[2. 0.]
     [0. 0.]]

为什么我们在 pass_by_ref_sideEffect 之后对 A 产生副作用而不是 pass_by_ref?

这与您传递变量的方式无关,而与赋值的工作方式有关。在 pass_by_ref() 中,这一行 A = np.ones((2,2)) 创建了一个新数组并将其分配给本地名称 A。原来的数组对象仍然存在,但A不再引用它。在另一种情况下,您通过使用 A[0][0] = 2.

分配给它的一个元素来操纵原始数组

如果你想在第一种情况下产生副作用,那么像这样分配给 A 的一片:

def pass_by_ref(A: np.array):
    A[:,:] = np.ones((2,2))
    return A

A = np.zeros((2,2))
B = pass_by_ref(A)

print(A)
[[1., 1.],
 [1., 1.]]

print(B)
[[1., 1.],
 [1., 1.]]

下面是一个示例,在不将变量传递给函数的情况下演示了这一点:

In [1]: import numpy as np

In [2]: A = np.zeros((2,2))

In [3]: B = A

In [4]: B
Out[4]:
array([[0., 0.],
       [0., 0.]])

In [5]: A[:,:] = np.ones((2,2))

In [6]: B
Out[6]:
array([[1., 1.],
       [1., 1.]])

当Python调用函数时,传递的是对象的引用。使用A[0][0] = 2赋值时,会根据变量A指向的对象地址进行偏移,找到要写入的地址。但是如果你使用A = np.ones((2, 2)),一个新的数组会被创建并使变量A指向它。