Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/303.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如果Python切片复制引用,为什么';我不能用它来修改原始列表吗?_Python_List_Reference - Fatal编程技术网

如果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
的第一项吗?@Heisenberg
l[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