处理numpy数组时赋值运算符中的指针行为?

Posted

技术标签:

【中文标题】处理numpy数组时赋值运算符中的指针行为?【英文标题】:Pointer-like behaviour in assignment operator when dealing with numpy arrays? 【发布时间】:2020-11-03 19:24:33 【问题描述】:

我偶然发现了赋值运算符 += 的一些奇怪行为,这完全让我感到困惑。看这段代码sn-p:


import numpy as np

def myalg(data, alpha, beta):

    adash=np.zeros(len(data))
    a=np.zeros_like(adash)
    a_=np.zeros_like(a)
    gain=1
    count=0

    while count<3:
        adash=adash+alpha*np.gradient(data)
        a_old=a
        print( a_old)
        #a+=alpha* (np.gradient(adash)+ alpha* data)
        a=a+alpha* (np.gradient(adash)+  alpha* data)
        print( a_old)
        a/=1+alpha*beta
        #a=a/(1+alpha*beta)
        print( a_old)
        a_=2*a-a_old
        
        gain=la.norm(a-a_old)
        count+=1 
        print(a)
        print(a_)
        print(adash)
        print(gain)

data=np.arange(6)
myalg(data, alpha=0.4, beta=0.25)

我原以为将“cmets”之一交换为上述替代行时不会发生任何变化。虽然a-array 在每种情况下确实是相同的,但代码确实改变了a_old: 选择a=a+... 时,a_old 保持不变,无论下面选择a/=a=a/... 中的哪一个。 在a+= 987654329 @时,a_old的行为a。所以print(a_old) 每次被调用时都会产生a 的值,直到a 被明确地分配一个新值(例如a= a/...,而不是像+=, -=, *=, /= 这样的赋值运算符)。

那么为什么数组会发生这种情况?

编辑:我知道它是如何发生的,但我不明白为什么会发生这种情况。 为什么这种行为不会发生,例如整数还是浮点数?

【问题讨论】:

您可以使用a_old = aprint(a_old),但此时a_old 尚未定义。这应该会导致 UnboundLocalError。还有什么是aprint?请注意,a += ... 会就地修改数组,而a = a + ... 会创建一个新副本。 我在您的代码中看不到任何 a*=...a=a*...。描述不清楚。 y=x 不进行复制。 y 引用与 x 相同的对象。如果y 发生突变,您也会看到x 的变化。数字是不可变的,数组(和列表)是可变的。 【参考方案1】:

请查看每行的 cmets 以了解行为不同的原因(注意:缩进是为了清楚起见,而不是为了编码):

#This points to `a`
a_old=a
print(a_old)

    #This changes `a` inplace so `a_old` will change too
    a+=alpha* (np.gradient(adash)+ alpha* data)
    
    #This creates a NEW `a`, therefore `a_old` will not change
    a=a+alpha* (np.gradient(adash)+  alpha* data)

print(a_old)

    #if you have used `a+=..` this changes `a` inplace again and so `a_old`
    #if you have used `a=a+..` this changes the NEW `a` and NOT the `a_old`
    a/=1+alpha*beta

    #this creates yet another NEWER `a` 
    #and hence `a_old` does not change beyond the LAST print
    a=a/(1+alpha*beta)

print(a_old)

【讨论】:

对 */-混淆感到抱歉,为了清楚起见,我对其进行了编辑。我已经意识到导致这种行为的过程,但是我不明白为什么其他对象(如浮点数/整数)不是这种情况...... 因为 float/int 数据类型不是指针,它总是在原地改变。虽然数组对象是指针,并且当您更改指针时,对象也会更改(指向内存中的不同位置)。另外,请查看***.com/help/someone-answers,了解如何接受关于 SO 的答案。谢谢 @Ehsan,我认为您的意思是浮点/整数数据类型 从不 就地更改。只有可变类型(如数组)可以就地更改。请注意,对于要就地更改的变量,该变量的id()(即它在内存中的位置)保持不变,而变量的内容会发生变化。

以上是关于处理numpy数组时赋值运算符中的指针行为?的主要内容,如果未能解决你的问题,请参考以下文章

在C语言中能否直接给指针指向的数据赋值?为啥?

Python机器学习(四十七)NumPy 副本和视图

加法赋值 += 表达式中的行为

NumPy学习笔记:3更加复杂的数组

C中的指针:分配内存与赋值VS分配内存而不赋值

Numpy:如何在 numpy 中选择项目并为其赋值