numpy 数组赋值问题

38 投票
2 回答
33705 浏览
提问于 2025-04-16 00:05

我在使用Python 2.6.5和Numpy时遇到了一个奇怪的问题。我给一个numpy数组赋值,然后把它的值赋给一个新变量。当我对这个新数组进行任何操作时,原来的数组的值也会改变。这是为什么呢?请看下面的例子。请帮我解答一下,因为我对Python和编程都还很陌生。

-Sujan

>>> import numpy as np
>>> a = np.array([[1,2],[3,4]])
>>> b = a
>>> b
array([[1, 2],
       [3, 4]])
>>> c = a
>>> c
array([[1, 2],
       [3, 4]])
>>> c[:,1] = c[:,1] + 5
>>> c

array([[1, 7],
       [3, 9]])
>>> b
array([[1, 7],
       [3, 9]])
>>> a
array([[1, 7],
       [3, 9]])

2 个回答

4

简单来说,给变量赋值就是创建一个新的指向已有对象的引用。

  A = object   # A points to object in memory
  B = A        # B points to the same object
72

其实这根本不是问题,这只是Python中数组(和其他对象)工作的方式。

可以这样理解:你在代码中创建的数组是一个存放在内存某个位置的对象。但是,你不能通过告诉Python去内存的哪个位置来使用它;你必须给它起个名字。当你写

a = np.array([[1,2],[3,4]])

时,你既是在创建数组,也是在给它起个名字,a,这个名字指向它。从那时起,Python就知道a指的是“内存地址0x123674283”(或者其他地址)。在Python运行时内部有一个表(如果我没记错的话叫“符号表”),里面包含了所有这些信息,所以在上面的Python代码执行后,这个表会包含

...,
'a' : 0x123674283,
...

当你把一个变量的值赋给另一个变量,比如

b = a

时,Python并不会复制整个数组,因为如果数组很大,那会花费很长时间。相反,它会去符号表中,复制a的内存地址到b的新行中。所以你最终得到的是

...,
'a' : 0x123674283,
...,
'b' : 0x123674283,
...

所以你看,ab实际上指向的是内存中的同一个位置,也就是同一个对象。你对其中一个所做的任何更改都会反映在另一个上,因为它们只是同一个东西的两个名字。

如果你想真正复制这个数组,你必须明确调用一个方法来做到这一点。Numpy数组有一个copy方法,可以用来实现这个目的。所以如果你写

b = a.copy()

那么Python会首先真正复制这个数组——也就是说,它会在内存中划出一个新的区域,假设地址是0x123904381,然后去内存地址0x123674283,把数组的所有值从那个内存区域复制到这个新的区域。所以你在内存中有两个不同地方存放着相同的内容。

...,
'a' : 0x123674283,
...,
'b' : 0x123904381,
...

现在,当你改变b的某个元素时,这个改变不会在a中显示,因为ab不再指向计算机内存的同一个区域。由于数组数据有两个独立的副本,你可以改变一个而不影响另一个。

撰写回答