【问题标题】:When do the Augmented Assignment operations behave as in-place operations and when do not?增强分配操作何时表现为就地操作,何时不表现为?
【发布时间】:2021-01-01 17:55:01
【问题描述】:

我一直都知道 Python 增强操作总是执行就地操作。但似乎并非适用于所有情况。当我在 integers 上应用增强操作时,它没有到位。

    var1 = 1234
    print(id(var1))
    var1 = var1 + 4321
    print(id(var1))

    print()

    var2 = 5678
    print(id(var2))
    var2 += 8765
    print(id(var2))

输出:

140272195234704
140272195234928

140272195234736
140272195234896    

但是当我将它应用于列表时,它就到位了。

    var1 = [1, 2]
    print(id(var1))
    var1 = var1 + [3]
    print(id(var1))

    print()

    var2 = [5, 6]
    print(id(var2))
    var2 += [7]
    print(id(var2))

输出:

140461597772992
140461597413184

140461597412480
140461597412480

我的问题是,它什么时候表现为就地操作,什么时候不表现为? 为什么?

【问题讨论】:

标签: python in-place augmented-assignment


【解决方案1】:

当你运行var1 = var1 + [3]时,Python首先执行右边的操作,然后将它赋值给左边的变量。它使用右侧的值的结果创建一个全新的列表,然后将其分配给左侧。旧列表和新列表不同是有道理的。事实上,如果你跑了:

var1 = [1, 2]
var2 = var1
var1 = var1 + [3]

var2 在第二条指令之后将具有与var1 相同的 id,var2 在第三条指令之后将继续具有相同的 id,而 var 的 id 会发生变化。

另一方面,var2 += [7] 表明可以重复使用相同的空间。在大多数情况下,列表上的 += 确实会重复使用相同的空间。

【讨论】:

  • @HeapOverflow。有什么更好的说法?从技术上讲,写“list.__add__ 不会发生变异,而 list.__iadd__ 会发生变异”是正确的答案,但我认为重要的信息在技术术语中迷失了。”
  • 糟糕。我的意思是extend。对于两边的列表,他们真的不使用相同的代码吗?
  • 编辑以包含您的 cmets。感谢您的帮助。
【解决方案2】:

对于整数,在这两种情况下都将一个整数替换为另一个整数,因为整数是不可变的。因为在这两种情况下,您都在谈论分配给变量的新对象,变量指向的 id 在两种情况下都会发生变化。

在第一个列表案例中,您实际上是在做同样的事情,用另一个列表替换一个列表,因为这就是 + 运算符所做的......它结合了两个操作数列表并返回一个新列表。

但在+= 的情况下,您不会更改var2 指向的列表,而只是操纵它指向的列表。列表是可以修改的可变对象。 += 运算符的作用类似于列表的 extend 方法,将提供的列表中的项目附加到现有列表中。因为var2指向的列表没有变化,所以id也没有变化。

【讨论】:

  • 糟糕。我的意思是extend。对于两边的列表,他们真的不使用相同的代码吗?
  • 这是使用 __iadd__ 方法(如果存在)或使用 __add__ 方法的简写。对于列表,我相信__iadd__ 最终在 C 代码中的某处使用与 extend 相同的代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-08
  • 2011-06-22
  • 2014-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多