Python 为什么b[:]=a变异了列表b?

Python 为什么b[:]=a变异了列表b?,python,python-3.x,list,slice,Python,Python 3.x,List,Slice,假设我们有一个列表a=[1,2,3],我需要将a的元素复制到新列表b 我们可以做a=b,但是a和b都指向同一个列表。因此,对其中任何一个进行变异都会对两个列表进行变异 >>> 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=[1,2,3]
,我需要将
a
的元素复制到新列表
b

我们可以做
a=b
,但是
a
b
都指向同一个列表。因此,对其中任何一个进行变异都会对两个列表进行变异

>>> 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
值创建不同的列表。现在,即使我变异了
a
b
也不会受到影响,反之亦然
b
b[:]
是两个不同的列表

>>> 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
b[:]
都指向不同的列表,对吗?如果我错了,请纠正我。如果我变异了
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

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

作为一个表达式,计算
b[:]
将生成一个新列表。但是,作为分配目标,分配给
b[:]
并不意味着“计算表达式
b[:]
,然后分配给结果列表”。无论如何,您不能在Python中指定对象

作为分配目标,分配给
b[:]
会告诉现有列表将其内容替换为分配给
b[:]
的任何内容的元素。这是通过
\uuuuu setitem\uuuuuuuuu
方法处理的,如
b.\uuuuu setitem\uuuuuuuuuu(slice(None,None),a)
。不会生成新列表,并且
b[:]
不会作为表达式计算


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

当用作表达式或赋值目标时,切片的含义不同

作为一个表达式,计算
b[:]
将生成一个新列表。但是,作为分配目标,分配给
b[:]
并不意味着“计算表达式
b[:]
,然后分配给结果列表”。无论如何,您不能在Python中指定对象

作为分配目标,分配给
b[:]
会告诉现有列表将其内容替换为分配给
b[:]
的任何内容的元素。这是通过
\uuuuu setitem\uuuuuuuuu
方法处理的,如
b.\uuuuu setitem\uuuuuuuuuu(slice(None,None),a)
。不会生成新列表,并且
b[:]
不会作为表达式计算



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

“现在,如果我执行b[:]=a我的列表b正在变异。“
没有完全变异,而是被另一个列表覆盖,该列表被重命名为
b
。我不是专家,但我假设当
b[:]
被指定时,它会修改列表
b
。但是,当在右侧调用
b[:]
时,它返回一个包含
b
的每个元素的列表,该列表指向不同的位置#@SayandipDutta绝对不是。
b
引用的列表正在发生变化。您混淆了两件事:切片和基于切片的分配。表达式
x[:]
创建了一个切片,隐式地调用
x.\uu getitem\uuuuu
,而语句
x[:]=b
是切片赋值,它调用
x.\uuu setitem\uuuu
@juanpa.arrivillaga感谢您花时间解释并找到了一个类似的问题。现在我明白了其中的区别。
“现在,如果我做了b[:]=a,我的列表b正在变异。”
没有完全变异,而是被另一个列表覆盖,该列表被重命名为
b
。我不是专家,但我假设当
b[:]
被分配到时,它会修改列表
b
。然而,当
b[:]
在右侧被调用,它返回一个包含
b
的每个元素的列表,该列表指向不同的位置#@SayandipDutta绝对不是。由
b
引用的列表正在发生变异。您混淆了两件事,切片和基于切片的赋值。表达式
x[:]
创建一个切片,隐式调用
x.\uuu getitem\uuu
,而语句
x[:]=b
是切片赋值,它调用
x.\uuuu setitem\uuuu
@juanpa.arrivillaga感谢您花时间解释并找到了一个类似的问题。现在我理解了区别。感谢这就是我要找的。非常清楚的解释。您所说的
在Python中不能赋值给对象是什么意思Spice:赋值给Python中的变量或属性,而不是对象。这与C++ C++的语言形成了对比。@ USER 357112SpPusiSMONICA HMM在C++中看起来是什么样子?我想我对此一无所知。谢谢!@威尔夏普:在Python中,如果您执行了<代码> A.B.C.<代码>,那么<代码> A<代码>负责重新绑定它的代码。<代码> B<代码>属性。在C++中,如果你做了代码> A.B.C;,那么<代码> A.B.< /Cord>对象负责修改它自己,使其看起来像“代码> C<代码>代码。谢谢。这就是我所要寻找的。非常清楚的解释。你说的是什么意思?<代码>你不能指派给Python中的对象,无论如何< /Cord> @ WelWHyp:分配给事物。与Python中的变量或属性一样,不是对象。这与C++ C++的语言形成了对比。@ USER 357112SpPusiSMONICA HMM在C++中是什么样子的?我想我对此一无所知。谢谢!@威尔夏普:在Python中,如果你执行了<代码> A.B= C <代码>,那么<代码> A<代码>