为什么python / numpy + =改变原始数组?

时间:2016-03-10 07:51:48

标签: python numpy

import numpy as np

W = np.array([0,1,2])
W1 = W
W1 += np.array([2,3,4])
print W

W = np.array([0,1,2])
W1 = W
W1 = W1 + np.array([2,3,4])
print W

上面的代码会改变W,但下面的代码不会改变W。为什么呢?

4 个答案:

答案 0 :(得分:5)

几乎任何类型的集合都是如此。这只是因为python处理变量的方式。 var1 += var2与带有集合的var1 = var1 + var2不同。据我所知,我会解释它,当然可以改进,所以欢迎任何编辑/批评。

print("1:")
x1 = [7]
y1 = x1
y1 += [3]
print("{} {}".format(x1, id(x1)))
print("{} {}".format(y1, id(y1)))

print("2:")
x2 = [7]
y2 = x2
y2 = y2 + [3]
print("{} {}".format(x2, id(x2)))
print("{} {}".format(y2, id(y2)))

输出:

1:
[7, 3] 40229784 # first id
[7, 3] 40229784 # same id
2:
[7]    40228744 # first id
[7, 3] 40230144 # new id

var1 = var1 + var2创建一个带有新ID的新对象。它接受旧值,将其添加到第二个变量,并使用第一个对象的NAME将其分配给新对象。在var1 += var2示例中,它只是将其附加到ID指向的对象,该对象与旧变量相同。

答案 1 :(得分:4)

的情况下
W = np.array([0,1,2])
W1 = W
W1 += np.array([2,3,4])

W指向内存中的某个位置,持有一个numpy数组。 W1指向同一位置。 W1 += np.array([2,3,4])将该位置记在内存中,并更改内容。

在这种情况下:

W = np.array([0,1,2])
W1 = W
W1 = W1 + np.array([2,3,4])

WW1 开始指向内存中的相同位置。然后创建一个新数组(W1 + np.array([2,3,4])),它位于内存中的新位置。 (请记住:始终首先评估右侧,然后将其分配给左侧的变量。)然后,使W1指向内存中的这个新位置(通过分配{ {1}}到这个新数组)。 W1仍然指向内存中的旧位置。从现在开始,WW不再是相同的数组。

答案 2 :(得分:1)

基本上,++=是任何类都可以实现的不同方法。在numpy中,+=实现了内存更改,而+返回一个新数组。

this question中的更多详情。

答案 3 :(得分:0)

在Python中,运算符+(加法)重定向到左操作数的__add__方法或右操作数的__radd__方法。我们可以忽略后一种情况,因为这种情况很少使用(当加法不通勤时)。

+=运算符重定向到__iadd__方法(如果已定义)。如果在左侧操作数上未定义__iadd__,则a += b等效于a = a + b

a += b要记住的是,它不仅是a.__iadd__(b)(或type(a).__iadd__(a, b)),还是a = type(a).__iadd__(a, b)。一方面,这种强制分配允许int之类的不可变类型定义有意义的+=操作。另一方面,即使发生了列表添加,以下操作也以TypeError失败:

tup = (['a'], ['b'])
tup[0] += ['c']

Numpy数组是易变的对象,它们在位置操作中已明确定义。如果ab是相同形状的数组,则a += b使用a作为输出缓冲区将两个数组加在一起。该操作的函数形式为a = np.ndarray.__iadd__(a, b),它修改a并返回a

类似地,a = a + b等同于a = np.ndarray.__add__(a, b)。与__iadd__不同,__add__创建并返回一个全新的数组来保存结果,然后将其分配给a

这对于诸如输出类型之类的东西还有一些其他含义。如果a具有dtype=int32,而b具有dtype=float64,则就地操作将不会更改a的类型。相反,b的值将被截断。 a + b的结果将具有较宽的类型,在此示例中为float64

所有基本的Python运算符在numpy中都有等效的函数实现。 a = a + b等同于a = np.add(a, b)a += b等同于a = np.add(a, b, out=a)