Python - 数组复制/分配,numpy的意外'=array [:]'行为

Posted

技术标签:

【中文标题】Python - 数组复制/分配,numpy的意外\'=array [:]\'行为【英文标题】:Python - array copying/assign, unexpected '=array[:]' behaviour for numpyPython - 数组复制/分配,numpy的意外'=array [:]'行为 【发布时间】:2020-08-12 10:55:48 【问题描述】:

我正在阅读有关通过引用或值复制数组 (&list) 的内容。但是,我在这里遇到了一个问题。为了展示我的问题,我做了三个示例,每个示例都有一个分配和一个更改。

第一个例子:默认是通过引用复制的。 因此,更改会影响 a 和 ArrayA,它们都具有相同的地址。好的

第二个例子: 由于首先计算右侧,*1 不会改变它的值,但会导致按值复制。 (我认为这也可以通过其他几种方式完成,例如使用 copy() 和 ..) 因此,更改只影响 c,具有与 ArrayC 不同的地址。好的

第三个​​例子: 据我所知,在这里我将 [:] 添加到数组中,从而复制数组(=按值)。可以通过e和ArrayE的不同地址来确认。但是,这种变化不仅影响 e,还影响 ArrayE。对我来说,这几乎是出乎意料的,因为它以前甚至向我显示了不同的地址。为什么?

谢谢你=)

import numpy as np
# Example 1, by reference
ArrayA = np.array([5,2,3,5,4])
ArrayB = np.array(  [1,2,3,4])

a = ArrayA
a[1:] += ArrayB

print(":\t,\tid: ".format("ArrayA",ArrayA, id(ArrayA) ))
print(":\t  ,\tid: ".format("ArrayB",ArrayB, id(ArrayB) ))
print(":\t,\tid: ".format("a",a, id(a) ))

ArrayC = np.array([5,2,3,5,4])
ArrayD = np.array(  [1,2,3,4])


# Example 2, by value
c = ArrayC*1
c[1:] += ArrayD

print()
print(":\t,\tid: ".format("ArrayC",ArrayC, id(ArrayC) ))
print(":\t  ,\tid: ".format("ArrayD",ArrayD, id(ArrayD) ))
print(":\t,\tid: ".format("c",c, id(c) ))

# Example 3, by reference/value?!?!
ArrayE = np.array([5,2,3,5,4])
ArrayF = np.array(  [1,2,3,4])

e = ArrayE[:]
e[1:] += ArrayF

print()
print(":\t,\tid: ".format("ArrayE",ArrayE, id(ArrayE) ))
print(":\t  ,\tid: ".format("ArrayF",ArrayF, id(ArrayF) ))
print(":\t,\tid: ".format("e",e, id(e) ))
ArrayA: [5 3 5 8 8],    id: 2450575020480
ArrayB:   [1 2 3 4],    id: 2450575021680
a:      [5 3 5 8 8],    id: 2450575020480

ArrayC: [5 2 3 5 4],    id: 2450575021280
ArrayD:   [1 2 3 4],    id: 2450575022080
c:      [5 3 5 8 8],    id: 2450575022240

ArrayE: [5 3 5 8 8],    id: 2450575022640
ArrayF:   [1 2 3 4],    id: 2450575022000
e:      [5 3 5 8 8],    id: 2450575022880

【问题讨论】:

“通过引用复制”不是一回事。您应该阅读nedbatchelder.com/text/names.html,然后重新提出您的问题。 它不是“引用复制”,它根本不是复制。请注意,这与传递引用和传递值无关,它们是评估策略,即函数的参数如何/何时的语义评估。请注意,Python 既不使用按值调用也不使用按引用调用 当您切片 numpy.ndarray 对象时,它会创建一个新的 array object,它是数组中底层缓冲区的 view切片。 【参考方案1】:

已编辑 - 请参阅下面的 @juanpa.arrivillaga 的 cmets。

在您的所有示例中,ndarraysnumpy.int32 对象,它们是可变。 因此,从您的第三个示例中,eArrayE 都指向相同的 numpy.int32 对象。 这就是为什么更改会同时反映在两者上的原因。 您可以通过检查他们的 id 来验证这一点。

print(id(e[0]) == id(ArrayE[0]))

【讨论】:

我说得对吗:所以使用 [:] 会产生一个不同的数组,正如我在 id(e) 中所做的不同地址所看到的那样。但是新数组的字段保持不变,正如您匹配的id(e[0])) 所示? @Wuhuu2 正确。如果您使用常规 python 列表而不是 numpy 数组,则值将是 int 类型,它是不可变的。因此,一个列表上的更改不会修改另一个列表。 不,数组中的值及其可变性无关紧要。在 python 中对列表进行切片会创建一个新列表对象,使用浅拷贝语义。 numpy.ndarray 的切片创建一个新数组对象,它是底层原始缓冲区的 视图 还要注意,数组实际上并不包含numpy.int32 对象。 numpy.ndarray 具有数字/结构化数据类型的对象本质上是原始类 C 数组的面向对象的包装器。 numpy.int32 和各种 dtypes 实际上仅在您访问要带入解释器级别的数组中的值时临时存在,有点像 Java 中的自动装箱。 @juanpa.arrivillaga 这更有意义。谢谢!

以上是关于Python - 数组复制/分配,numpy的意外'=array [:]'行为的主要内容,如果未能解决你的问题,请参考以下文章

NumPy 数组和 python 列表有啥区别? [复制]

向Python numpy数组分配元素的问题

python - 重复numpy数组而不复制数据

python numpy数组中的复制问题

序列化 Numpy 数组的意外行为

python - 如何在python numpy中标准化二维数组的一维? [复制]