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
。为什么呢?
答案 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])
W
和W1
开始指向内存中的相同位置。然后创建一个新数组(W1 + np.array([2,3,4])
),它位于内存中的新位置。 (请记住:始终首先评估右侧,然后将其分配给左侧的变量。)然后,使W1
指向内存中的这个新位置(通过分配{ {1}}到这个新数组)。 W1
仍然指向内存中的旧位置。从现在开始,W
和W
不再是相同的数组。
答案 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数组是易变的对象,它们在位置操作中已明确定义。如果a
和b
是相同形状的数组,则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)
。