如果Python切片复制引用,为什么';我不能用它来修改原始列表吗?
我知道 但是如果是这样的话,为什么这不起作用呢如果Python切片复制引用,为什么';我不能用它来修改原始列表吗?,python,list,reference,Python,List,Reference,我知道 但是如果是这样的话,为什么这不起作用呢 l = [1, 2, 3] # Attempting to modify the element at index 1 l[0:2][-1] = 10 # but the attempt fails. The original list is unchanged l > [1, 2, 3] l[0:2][1]是否应该指向原始列表索引1处的元素?切片列表返回一个新的浅复制列表对象。虽然它没有深度复制原始列表的项目是正确的,但结果是一个全新
l = [1, 2, 3]
# Attempting to modify the element at index 1
l[0:2][-1] = 10
# but the attempt fails. The original list is unchanged
l
> [1, 2, 3]
l[0:2][1]
是否应该指向原始列表索引1处的元素?切片列表
返回一个新的浅复制列表
对象。虽然它没有深度复制原始列表的项目是正确的,但结果是一个全新的列表
与原始列表不同
见:
所有切片操作都返回一个包含请求元素的新列表。这意味着以下切片将返回列表的浅层副本:
>>> squares = [1, 4, 9, 16, 25]
>>> squares[:]
[1, 4, 9, 16, 25]
考虑
>>> squares[:] is squares
False
为了更好地解释它,假设你写了
l = [1, 2, 3]
k = l[0:2]
k[-1] = 10
我希望你能同意这是等效的
现在,让我们将各个语句分解为:
l=[1,2,3]
这将创建以下对象和参照:
id对象
-- --------
0
1.
2.
3.
名称→ 身份证件
---- --
L→ 3.
l[0]→ 0
l[1]→ 1.
l[2]→ 2.
k=l[0:2]
这将创建一个新列表
,其中包含l
中所含引用的副本:
id object
-- --------
0 <int 1>
1 <int 2>
2 <int 3>
3 <list A>
4 <list B>
名称→ 身份证件
---- --
L→ 3.
l[0]→ 0
l[1]→ 1.
l[2]→ 2.
K→ 4.
k[0]→ 0
k[1]→ 5.
注意
l
和l[0]
到l[2]
如何不受此影响。QED.您是对的,切片不会复制列表中的项目。但是,它确实创建了一个新的列表对象
你的评论暗示了一种误解:
# Attempting to modify the element at index 1
l[0:2][-1] = 10
这不是对元素的修改,而是对列表的修改。换句话说,它实际上是“更改列表,使索引1现在指向数字10”。由于您的切片创建了一个新列表,您只需将该新列表更改为指向其他对象
在你对oldrinb回答的评论中,你说:
为什么l[0:1]
和l[0:1][0]
不同?它们不应该都指向同一个对象,即l
的第一项吗
除了l[0:1]
是一个列表而l[0:1][0]
是一个单一元素这一事实之外,这里还有同样的误解。假设some_list
是一个列表,索引ix
处的对象是obj
。这:
some_list[ix] = blah
。是对某个列表的操作。不涉及对象obj
。这可能会令人困惑,因为它意味着某些列表[ix]
的语义稍有不同,这取决于它位于赋值的哪一侧。如果你这样做
blah = some_list[ix] + 2
。然后您确实在列表中的对象上操作(即,它与obj+2
相同)。但是,当索引操作位于赋值的左侧时,它不再涉及包含的对象,只涉及列表本身
指定给列表索引时,您是在修改列表,而不是其中的对象。因此,在您的示例中,
l[0]
与l[0:2][0]
相同,但这并不重要;因为您的索引是一个赋值目标,所以它正在修改列表,而不关心列表中已经有什么对象。您不能修改元素本身;它是不变的。分配给列表的一个元素会将一个引用替换为另一个引用。此外,“复制列表”(浅拷贝)和“复制列表的对象”(深拷贝)之间也有区别。即使切片是一个新列表,它仍然包含对旧对象的引用。(这就是我认为“浅拷贝”的意思。)考虑到l=[1,2,3],这是有道理的;l[0:1]=[10]
会修改列表。但是,l[0:1][0]=[10]
不会修改列表。为什么l[0:1]
和l[0:1][0]
不同?它们不应该都指向同一个对象,即l
的第一项吗?@Heisenbergl[0:1]=[10]
不是从切片
构造一个新的列表
——它是使用切片
分配给现有的列表
。另一方面,l[0:1][0]=10
首先使用slice
构造一个新的列表
,然后使用一个简单的索引(0
)分配给它的第一个元素。区别在于l[0:1]=[10]
相当于l.\uu setitem_uuuuu(slice(0,1),[10])
而l[0:1][0]=10
类似于l.\uu getitem\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu;但是,在第二种情况下,您将从l.对新创建的列表进行变异。为了更清楚地看到发生了什么,考虑引入一个中间变量,如SO:<代码> L2= L[0:1];l2[0]=10
。检查l2
之后,您会注意到l2==[10]
与l
是unchanged@Heisenberg当前位置我添加了一个可能澄清问题的答案。主要的一点是,当您指定给列表索引时,您不会影响列表中的对象;你只是在修改列表本身(所以你在修改你的切片创建的新列表)。接受这个答案,因为这是我误解的核心。非常感谢。
# Attempting to modify the element at index 1
l[0:2][-1] = 10
some_list[ix] = blah
blah = some_list[ix] + 2