【问题标题】:Python in place object update in a for loopPython 在 for 循环中就地更新对象
【发布时间】:2017-08-10 22:57:15
【问题描述】:

在 Python >= 3.5 中:

x = np.zeros((2,3))
for x_e in x:
    x_e += 123

此操作返回所有1232x3 矩阵。而以下返回全零:

x = np.zeros((2,3))
for x_e in x:
    x_e = 123

这对我来说有点不妥,因为 x_ex 的一个元素,而且它并不完全感觉 x 正在更新。

好的,我认为这是一个东西,它被称为“就地”更新? (类似于就地算法?)

但是,令人震惊的是这不适用于列表:

x = [0,0,0]
for x_e in x:
    x_e += 123

这会返回列表

[0, 0, 0]

如果有人能告诉我这里到底发生了什么,我将不胜感激。

【问题讨论】:

标签: python python-3.x numpy


【解决方案1】:

想象一下你有这个:

>>> x = np.array(range(5))
>>> x
array([0, 1, 2, 3, 4])

那么现在:

>>> x+123
array([123, 124, 125, 126, 127])

如您所见,“+”操作已映射到数组。所以当你这样做时 创建一个全为 0 的数组,并将 123 添加到该数组所组成的子列表中,得到上述结果是合乎逻辑的。

【讨论】:

  • 是的,但是,为什么 in place for 循环操作不适用于列表?对我来说新的是 for 循环中的就地操作。我确实了解广播,因为我来自 Matlab。
  • @CemS。这是因为您在 for 循环中更改了一个可变对象,它是主列表的子列表,并更改了一个可变对象,它是对原始对象的引用,对它的任何更改也会影响原始对象。
  • @CemS.,是的,在 python 列表和 numpy 数组中不是一回事。例如,列表与数组的另一个重大区别是内置函数(如 sum)在列表中的执行速度比数组快得多。我们只是将 np.arrays 用于大数据
  • @coder 在这种情况下它们是相同的,这只是可变性的问题而不是它们的功能。
  • @Kasramvd,是的,我同意我只是想澄清一下,一般情况是列表和 numpy 数组并不总是一回事
【解决方案2】:

在第一个 sn-p 中,您对 ndarray 对象执行就地添加。由于每个x_e 都是ndarray,因此就地操作成功并更改了元素。

在第二个 sn-p 中,您只是在重新评估循环变量。没有对x 的元素执行任何操作。

在第三个 sn-p 中,您没有多维列表,因此每个 x_e 实际上是一个 int。在 int 上使用 += 不会原地更改,它会返回一个新的整数对象(您不存储它)。

以下可能与第一个更相关:

x = [[0, 0, 0] for _ in range(3)]
for x_e in x:
    x_e += [123]

这里x 的每个元素都是一个list 对象[0, 0, 0],您可以在其上就地添加元素123。执行后,x 将是:

[[0, 0, 0, 123], [0, 0, 0, 123], [0, 0, 0, 123]]

【讨论】:

  • 感谢您的回答,这就是我想澄清的。但是,我能问一下为什么我们不能就地更改 int 吗?
  • @CemS。因为int 对象是不可变的,所以语言的设计者很早就做出了这个决定,因为它有很多好处。
  • @Kasramvd,谢谢!这说明了这个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-08
相关资源
最近更新 更多