变量克隆行为的不明确性

时间:2015-05-07 14:44:41

标签: python list python-2.7 operators in-place

除了一本书,我还提供了一个Python程序,我现在正在深入挖掘。

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

a = globdat.array

然后在下面的while循环中,每次迭代都会根据以下内容更新变量a

a[:] += da[:]

此操作的结果是globdat.array已更新,这将在后续操作中使用。

此处是否需要使用[:],还是仅用于表示它还会克隆到globdat.array?任何人都可以澄清这种编码风格吗?

3 个答案:

答案 0 :(得分:4)

这句话很讨厌:

a[:] += da[:]

它转化为:

a.__setitem__(slice(None),
              a.__getitem__(slice(None)).__iadd__(da.__getitem__(slice(None))))

这会使两个列表都不必要的副本。

假设ada是列表,您可以更合理地使用extend()方法:

a.extend(da)

答案 1 :(得分:4)

如果要修改列表,而不是用新列表替换它,则需要使用切片语法。

data <- sub240
while(rsquared.differ > 0.00001 && niter <=30){
    # do stuff
}

在这种情况下,a[:] = da[:] 总是修改列表,因此切片是多余的。

这可能是cargo cult programming的完美示例。

答案 2 :(得分: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. 的副本
  3. da连接到a2到位
  4. return a2
  5. 然后是作业a[:] = ...

    1. a中的所有值替换为a2中的所有值。
    2. 这样也达到了原来的目标,但效率却低得多。

      this question的答案中有关于这些内容的一些有趣的细节。