nis*_*sah 51 python arrays numpy
我碰到一个事实,即来到numpy阵列通过引用在多个地方通过,但后来当我执行下面的代码,为什么会出现的行为之间的差异foo和bar
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.而且,arr是foo函数范围内的局部变量名.一旦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 通过引用传递数组:
$: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可以被巧妙地做你想做的事情。
| 归档时间: |
|
| 查看次数: |
29550 次 |
| 最近记录: |