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

nis*_*sah 51 python arrays numpy

我碰到一个事实,即来到numpy阵列通过引用在多个地方通过,但后来当我执行下面的代码,为什么会出现的行为之间的差异foobar

import numpy as np

def foo(arr):
   arr = arr - 3

def bar(arr):
   arr -= 3

a = np.array([3, 4, 5])
foo(a)
print a # prints [3, 4, 5]

bar(a)
print a # prints [0, 1, 2]
Run Code Online (Sandbox Code Playgroud)

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

unu*_*tbu 64

在Python中,所有变量名都是对值的引用.

当Python评估赋值时,右侧在左侧之前进行求值.arr - 3创建一个新数组; 它不会arr就地修改.

arr = arr - 3使局部变量arr引用这个新数组.它不会修改arr传递给它的最初引用的值foo.变量名arr只是绑定到新数组,arr - 3.而且,arrfoo函数范围内的局部变量名.一旦foo函数完成,就没有更多的引用了arr,Python可以自由地收集它引用的值.正如Reti43指出的那样,为了使arr价值受到影响a,foo必须返回arr并且a必须分配给该值:

def foo(arr):
    arr = arr - 3
    return arr
    # or simply combine both lines into `return arr - 3`

a = foo(a)
Run Code Online (Sandbox Code Playgroud)

相比之下,arr -= 3哪个Python转换为对__iadd__特殊方法的调用,确实会修改arr就地引用的数组.

  • 等待通过引用python中的函数传递的对象...? (2认同)

小智 8

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


don*_*lan 7

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.]])
Run Code Online (Sandbox Code Playgroud)

最重要的答案是指即使在编译的 c 代码中也会发生的现象,因为任何 BLAS 事件都将涉及“读取”步骤,其中形成用户(在这种情况下为代码编写者)知道的新数组,或者在用户不知道的临时变量中“幕后”形成一个新数组(您可能将其视为.eval()调用)。

但是,我可以清楚地访问数组的内存,就好像它位于比调用的函数(即setx(...))更全局的范围内;就编写代码而言,这正是“通过引用传递”的含义。


让我们再做一些测试来检查已接受答案的有效性:

(continuing the session above)
>>> def minus2(x):
...    x[:,:] -= 2
...
>>> minus2(x)
>>> x
array([[-1.,-2.],[-2.,-2.]])
Run Code Online (Sandbox Code Playgroud)

似乎是通过引用传递的。让我们做一个计算,它肯定会在引擎盖下计算一个中间数组,看看 x 是否被修改为好像它是通过引用传递的:

>>> def pow2(x):
...    x = x * x
...
>>> pow2(x)
>>> x
array([[-1.,-2.],[-2.,-2.]])
Run Code Online (Sandbox Code Playgroud)

嗯,我以为 x 是通过引用传递的,但也许不是?-- 不,在这里,我们用一个全新的声明(通过 python 中的解释隐藏)隐藏了 x,并且 python 不会将此“隐藏”传播回全局范围(这将违反 python 用例:即,成为初学者仍然可以被专家有效使用的编码语言)。

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

>>> def refpow2(x):
...    x *= x
...
>>> refpow2(x)
>>> x
array([[1., 4.],[4., 4.]])
Run Code Online (Sandbox Code Playgroud)

所以你看到python可以被巧妙地做你想做的事情。