变量克隆行为不清楚

4

我现在正在深入研究一本书附带的Python程序。

该程序使用一个名为globdat的全局数据结构,在特定的例程中,globdat内部的一个numpy数组被分配给一个局部变量:

a = globdat.array

然后在接下来的while循环中,变量a会根据以下方式在每次迭代中更新:

a[:] += da[:]

这个操作的结果是更新了globdat.array,而这个数组会在后续操作中使用。这里是否需要使用[:],还是仅仅为了表明它也对globdat.array进行克隆?有人能解释一下这种编码风格吗?

“globdat.array” 是 Python 列表还是 Numpy 数组或其他什么类型?这很重要。 - Stefan Pochmann
@StefanPochmann globdat.array 确实是一个 numpy 数组。如果这改变了提供的答案的相关性,我很抱歉。 - Steyn W.
他们似乎仍然对主要问题正确,但我是一个numpy新手,不能确定。我会问最佳回答者,因为我也很感兴趣。 - Stefan Pochmann
3个回答

4
这个声明相当刻薄:
a[:] += da[:]

它翻译成这样:
a.__setitem__(slice(None),
              a.__getitem__(slice(None)).__iadd__(da.__getitem__(slice(None))))

这样会产生不必要的两个列表副本。
假设ada是列表,你可以更合理地使用extend()方法:
a.extend(da)

4
如果您想就地修改列表,而不是用新列表替换它,则需要使用切片语法。
a[:] = da[:]

在这种情况下,+=总是会就地修改列表,因此切片是多余的。
这可能是模拟航空母舰编程的完美例子。

4
右侧的第二个[:]是多余的。它只是在连接之前复制了da,这是没有意义的。
现在我们只需要:
a[:] += da

首先,让我们了解一下 a += da 的作用。它相当于执行以下操作:
a = a.__iadd__(da)

调用__iadd__会扩展原始列表a并返回self,即对列表的引用。在这种情况下,之后发生的赋值没有任何效果(与a=a相同)。

这实现了原始目标,即扩展全局数组。


那么,a[:] += da是什么意思?它映射到:

a[:] = a[:].__iadd__(da)

或者更加繁琐的方法:
a.__setitem__(slice(None), a.__getitem__(slice(None)).__iadd__(da))

为了易读性,让我们将其写成以下形式(不是有效的Python语法):

a.__setitem__(:, a.__getitem__(:).__iadd__(da))

所以,a[:].__iadd__(da)
  1. 创建一个 a 的副本(称为 a2
  2. da 归并到 a2
  3. 返回 a2
然后赋值操作 a[:] = ...
  1. 就地用 a2 中所有的值替换 a 中所有的值。
所以,这也实现了原始目标,但效率要低得多。
有关此内容的一些有趣细节在此问题的答案中。

你能否判断对于numpy数组(或数组和列表混合使用)使用“slicings”是否有意义?问题的提问者确认了我的猜想并更新了问题,我也很好奇。 - Stefan Pochmann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接