让我们看下一段代码:
Try it online!
import numpy as np
def change(in_array, variant = 0):
if variant == 0:
in_array += 1 # line a
elif variant == 1:
in_array = in_array + 1 # line b
elif variant == 2:
in_array[:] = in_array + 1
elif variant == 3:
np.put(in_array, np.arange(in_array.size), in_array + 1)
elif variant == 4:
np.copyto(in_array, in_array + 1)
elif variant == 5:
np.place(in_array, np.ones_like(in_array), in_array + 1)
else:
assert False, variant
print('after, inside', in_array)
orig = np.array([1, 2, 3])
for variant in [0, 1, 2, 3, 4, 5]:
print('variant', variant)
x = np.copy(orig)
print('before', x)
change(x, variant)
print('after, outside', x, ('changed', 'not changed')[bool(np.all(x == orig))])
它输出:
variant 0
before [1 2 3]
after, inside [2 3 4]
after, outside [2 3 4] changed
variant 1
before [1 2 3]
after, inside [2 3 4]
after, outside [1 2 3] not changed
variant 2
before [1 2 3]
after, inside [2 3 4]
after, outside [2 3 4] changed
variant 3
before [1 2 3]
after, inside [2 3 4]
after, outside [2 3 4] changed
variant 4
before [1 2 3]
after, inside [2 3 4]
after, outside [2 3 4] changed
variant 5
before [1 2 3]
after, inside [2 3 4]
after, outside [2 3 4] changed
您可能会看到变体 0 在内外回答后给出正确的答案。而变体 1 仅在内部给出正确的。
这是因为变体 0 修改了函数中提供的实际给定数组。虽然变体 1 在函数内部创建了一个修改后的副本,该副本仅保留在函数内部,但实际传递的参数没有被修改。
所以变体 0 修改了传递的参数,而变体 1 修改了传递参数的副本。
在 Python 代码中,函数内部的 a = a + 1 实际上会在函数中创建变量 a 的副本。并且这个局部变量只保留到函数结束,并在函数运行结束时被删除。
变体2,a[:]创建原始数组的视图,它就像对原始数组元素子集的引用,只是:是整个数组的视图,分配给这个视图会修改原始数组。可修改视图也由 a[1:3] 之类的切片和 a[2] 或 a[[1,2]] 之类的索引创建。
写a[:] = some_operation(a) 可能是最直观、最快捷的将a 的修改/转换副本分配回a 的方法。
变体 3、4、5 是将右侧表达式分配回数组 a 的其他奇特方式。