Python通过引用传递数组:
$:python
...python startup message
>>> import numpy as np
>>> x = np.zeros((2,2))
>>> x
array([[0.,0.],[0.,0.]])
>>> def setx(x):
... x[0,0] = 1
...
>>> setx(x)
>>> x
array([[1.,0.],[0.,0.]])
顶级答案提到的现象即使在编译后的 c 代码中也会发生,因为任何 BLAS(Basic Linear Algebra Subprograms)事件都将涉及“读取”步骤,在此步骤中,要么形成一个新数组,用户(本例中的代码编写者)知道这一点,要么形成一个在临时变量中“隐藏”的新数组,用户并不知道这一点(您可能会看到这样的
.eval()
调用)。
然而,我可以清楚地访问数组的内存,就像它在比调用函数更全局的作用域中一样(例如
setx(...)
),这正是“按引用传递”在编写代码方面的意义。
接下来,我们进行几个测试以检查所接受答案的有效性:
(continuing the session above)
>>> def minus2(x):
... x[:,:] -= 2
...
>>> minus2(x)
>>> x
array([[-1.,-2.],[-2.,-2.]])
似乎是按引用传递。让我们进行一项计算,它肯定会在幕后计算出一个中间数组,并查看x是否像按引用传递一样被修改:
>>> def pow2(x):
... x = x * x
...
>>> pow2(x)
>>> x
array([[-1.,-2.],[-2.,-2.]])
哦,我以为 x 是按引用传递的,但也许不是?-- 不是的,在这里,我们使用全新的声明遮蔽了 x(在 Python 中通过解释隐藏),Python 不会将此“遮蔽”传播回全局范围(这会违反 Python 的使用情况:即成为一种初学者级别的编程语言,但仍可被专家有效地使用)。
然而,我可以很容易地通过强制修改内存(当我将 x 提交给函数时不会复制)来以“按引用传递”的方式执行此操作:
>>> def refpow2(x):
... x *= x
...
>>> refpow2(x)
>>> x
array([[1., 4.],[4., 4.]])
所以你可以看到,Python可以进行一些微调来实现你想要的功能。