“for”循环中的 i = i 1 和 i = 1 有什么区别?

新手上路,请多包涵

我今天发现了一件奇怪的事情,想知道是否有人可以阐明这里的区别是什么?

 import numpy as np

A = np.arange(12).reshape(4,3)
for a in A:
    a = a + 1

B = np.arange(12).reshape(4,3)
for b in B:
    b += 1

运行每个 for 循环后, A 没有改变,但是 B 已经为每个元素添加了一个。我实际上使用 B 版本写入 for 循环中的初始化 NumPy 数组。

原文由 Dammi 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 613
2 个回答

不同之处在于,一个修改数据结构本身(就地操作) b += 1 而另一个只是 重新分配 变量 a = a + 1


只是为了完整性:

x += y 并不总是 在进行就地操作,有(至少)三个例外:

  • If x doesn’t implement an __iadd__ method then the x += y statement is just a shorthand for x = x + y .如果 x 类似于 int --- 就会出现这种情况。

  • 如果 __iadd__ 返回 NotImplemented ,Python 回落到 x = x + y

  • __iadd__ 方法理论上可以实施,但不能在适当的地方工作。不过,这样做真的很奇怪。

碰巧你的 b s 是 numpy.ndarray s 实现 __iadd__ 并返回它自己所以你的第二个循环修改原始数组。

您可以在 “模拟数字类型”的 Python 文档中 阅读更多相关信息。

These [ __i*__ ] methods are called to implement the augmented arithmetic assignments ( += , -= , *= , @= , /= , //= , %= , **= , <<= , >>= , &=^=|= )。这些方法应尝试就地执行操作(修改自身)并返回结果(可以是但不一定是自身)。如果未定义特定方法,则扩充赋值会回退到普通方法。例如,如果 x 是具有 __iadd__() 方法的类的实例,则 x += y 等同于 x = x.__iadd__(y) 。否则,考虑 x.__add__(y)y.__radd__(x) e— ,与 — 的评估 x + y 。在某些情况下,扩充赋值会导致意外错误(请参阅 为什么 a_tuple[i] += ["item"] 在加法工作时引发异常? ),但这种行为实际上是数据模型的一部分。

原文由 MSeifert 发布,翻译遵循 CC BY-SA 3.0 许可协议

在第一个示例中,您重新分配变量 a ,而在第二个示例中,您使用 += 运算符就地修改数据。

请参阅有关 7.2.1 的部分。增强赋值语句

x += 1 这样的增强赋值表达式可以重写为 x = x + 1 以实现类似但不完全相同的效果。在增强版本中,x 仅被评估一次。 此外,在可能的情况下,实际操作就地执行,这意味着不是创建新对象并将其分配给目标,而是修改旧对象。

+= 接线员呼叫 __iadd__ 。此函数就地进行更改,并且只有在执行后,结果才会设置回您正在“应用” += 的对象。

__add__ 另一方面获取参数并返回它们的总和(不修改它们)。

原文由 Maroun 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题