numpy数组是通过引用传递的吗?

时间:2012-07-20 19:28:33

标签: python arrays numpy

我发现numpy数组在多个位置通过引用传递,但是当我执行以下代码时,为什么foo和{{1}的行为之间存在差异? }}

bar

我正在使用python 2.7和numpy版本1.6.1

3 个答案:

答案 0 :(得分:62)

在Python中,all variable names are references to values

当Python评估作业时,the right-hand side is evaluated before the left-hand sidearr - 3创建一个新数组;它不会就地修改arr

arr = arr - 3使局部变量arr引用此新数组。它不会修改传递给arr的{​​{1}}最初引用的值。变量名foo只是绑定到新数组arr。此外,arr - 3arr函数范围内的局部变量名。一旦foo函数完成,就不再有foo的引用,Python可以自由地收集它引用的值。 As Reti43 points out,要使arr的值影响arra必须返回foo,并且arr必须分配给该值:

a

相比之下,Python def foo(arr): arr = arr - 3 return arr # or simply combine both lines into `return arr - 3` a = foo(a) 转换为对__iadd__ special method的调用,确实会修改arr -= 3引用的数组。

答案 1 :(得分:8)

第一个函数计算(arr - 3),然后为其分配本地名称arr,这不会影响传入的数组数据。我的猜测是在第二个函数{{1}覆盖np.array运算符,并在数组数据上运行。

答案 2 :(得分:2)

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事件都将涉及“读入”步骤,在此步骤中,将形成一个由用户(在这种情况下为代码编写者)组成的新数组知道,或者在用户不知道的临时变量中“在幕后”形成了一个新数组(您可能将其视为.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是通过引用传递的,但也许不是吗? -不,在这里,我们用一个全新的声明(在python中通过解释将其隐藏)遮盖了x,并且python不会将此“阴影”传播回全局范围(这将违反python用例:即,成为一种入门级的编码语言,专家仍然可以有效地使用它。)

但是,通过强制修改内存(将x提交给函数时不会复制),我可以很容易地以“引用传递”的方式执行此操作:

>>> def refpow2(x):
...    x *= x
...
>>> refpow2(x)
>>> x
array([[1., 4.],[4., 4.]])

因此,您会发现可以对python进行一些细化以完成您想做的事情。