【问题标题】:Why b[:]=a mutates list b? [duplicate]为什么 b[:]=a 会改变列表 b? [复制]
【发布时间】:2020-05-02 01:16:57
【问题描述】:

假设我们有一个列表a=[1,2,3],我需要将a 的元素复制到新列表b

我们可以使用a=b,但ab 都指向同一个列表。因此,改变其中任何一个都会改变两个列表。

>>> a=b
>>> a
[1, 2, 3]
>>> b
[1, 2, 3]
>>> b.append(4)
>>> a,b
([1, 2, 3, 4], [1, 2, 3, 4])
>>> a.append(5)
>>> a,b
([1, 2, 3, 4, 5], [1, 2, 3, 4, 5])
>>> a is b
True
>>> id(a),id(b)
(2287659980360, 2287659980360)

为避免这种情况,我们可以使用b=a[:]a[:] 使用相同的 a 值创建一个不同的列表。现在,即使我改变了ab 也不会受到影响,反之亦然。 bb[:] 是两个不同的列表。

>>> b=a[:]
>>> a,b
([1, 2, 3, 4, 5], [1, 2, 3, 4, 5])
>>> a.append(6)
>>> a,b
([1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5])
>>> b.append(6)
>>> a,b
([1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6])
>>> a is b
False
>>> id(a),id(b)
(2287659980360, 2287653308552)

现在,如果我这样做 b[:]=a 我的列表 b 正在发生变异。但是b[:] 是另一个列表,对吗? bb[:] 都指向不同的列表,对吗?如果我错了纠正我。如果我变异b[:],为什么b 会被更改。我错过了什么?

>>> a=['a','b','c']
>>> b[:]=a
>>> a,b
(['a', 'b', 'c'], ['a', 'b', 'c'])
>>> id(b),id(b[:])
(2287653308552, 2287660267080)
>>> b is b[:]
False

【问题讨论】:

  • "Now, if I do b[:]=a my list b is being mutated." 没有完全变异,而是被另一个列表覆盖,该列表重命名为b
  • 不是专家,但我假设当b[:] 被分配到时,它会修改列表b。但是,当在右侧调用b[:] 时,它会返回一个包含b 的每个元素的列表,该列表指向不同的位置#
  • @SayandipDutta 绝对不是。 b 引用的列表正在发生变化。
  • 您混淆了两件事,切片和基于切片的分配。表达式x[:] 创建一个切片,隐式调用x.__getitem__,而语句x[:] = b 是切片赋值,调用x.__setitem__
  • @juanpa.arrivillaga 感谢您抽出时间来解释并找到类似的问题。现在我明白了其中的区别。

标签: python python-3.x list slice


【解决方案1】:

当用作表达式或用作赋值目标时,切片意味着不同的东西。

作为表达式,计算 b[:] 会生成一个新列表。但是,作为赋值目标,赋值给b[:]并不意味着“评估表达式b[:],然后赋值给结果列表”。无论如何,你不能分配给 Python 中的对象。

作为分配目标,分配给b[:] 告诉现有列表用您分配给b[:] 的任何元素替换其内容。这由__setitem__ 方法处理,如b.__setitem__(slice(None, None), a)。不会生成新列表,并且b[:] 不会被评估为表达式。

您可以在language reference documentation for assignment statements 中看到这一点,在“如果目标是切片”下(尽管切片分配的一些约束没有文档描述的那么严格;例如,文档说序列类型需要匹配,但对于大多数类型,它们不需要)。

【讨论】:

  • 谢谢,这正是我想要的。很清楚的解释。
  • You can't assign to objects in Python, anyway是什么意思
  • @Willwsharp:赋值分配给 Python 中的变量或属性之类的东西,而不是对象。这与 C++ 等语言形成鲜明对比。
  • @user2357112supportsMonica 嗯,这在 C++ 中是什么样子的?我想我在这方面是空白的。谢谢!
  • @Willwsharp:在 Python 中,如果你使用a.b = c,那么a 负责重新绑定它的b 属性。在 C++ 中,如果您执行a.b = c;,则a.b 对象负责将自身修改为类似于c
猜你喜欢
  • 2022-12-12
  • 2021-10-06
  • 2019-10-27
  • 2014-03-29
  • 2011-08-10
  • 2013-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多