我遇到了以下代码(有点):
my_list = [1, [2, 3, 4], 5]
my_list[1:2] = my_list[1]
运行这两行后,变量my_list
将为[1, 2, 3, 4, 5]
。对扩展嵌套列表非常有用。
但为什么它实际上做它的作用呢?
我会假设语句my_list[1:2] = my_list[1]
会执行以下操作之一:
[2, 3, 4]
放入列表中的第二个位置(已经存在的位置)my_list[1:2]
)时出现“解包太多值”错误。 (使用Numpy数组而不是列表重复上述操作会导致类似的错误。)其他问题(例如How assignment works with python list slice)往往不太关注要替换的切片大小与您要替换它的项目的大小之间的差异。 (更别说解释它为什么会这样运作了。)
答案 0 :(得分:5)
Slice assignment使用右侧的iterable替换列表的指定部分,其可能具有与切片不同的长度。从表面上看问题,之所以如此,是因为它很方便。
您实际上并未分配切片,即Python不会生成包含列表中指定值的切片对象,然后更改这些值。一个不起作用的原因是切片返回一个新列表,因此该操作不会改变原始列表。
另见this question,强调切片和切片分配完全不同。
答案 1 :(得分:2)
简答:
my_list[1:2] = my_list[1]
会将第一个索引中的内容替换为my_list
的第二个索引,并将第一个索引中的内容替换为my_list
强>
说明:
让我们看看两个切片操作,非常相似但完全不同
此创建列表副本并将其存储为变量
some_variable = some_list[2:5]
此会替换列表 inplace 的内容,这也允许更改列表的长度。
some_list[2:5] = [1, 2, 3, 4]
使用赋值运算符=
时,它会调用__setitem__
函数。我们的重点是上面的案例2。根据{{3}}文档:
如果目标是切片:引用中的主表达式是 评估。它应该产生一个可变序列对象(例如列表)。 分配的对象应该是相同类型的序列对象。 接下来,在此范围内评估下限和上限表达式 他们在场;默认值为零和序列的长度。该 边界应该评估为整数。如果任何一个是负的,那么 序列的长度被添加到它。生成的边界被剪切为 介于零和序列的长度之间,包括在内。最后, 要求序列对象用该项替换切片 分配顺序。切片的长度可以与切片的长度不同 分配序列的长度,从而改变了长度 目标序列,如果目标序列允许的话。
在我们的案例my_list[1:2] = my_list[1]
中,python还会将Python's Assignment Statement称为:
my_list.__setitem__(slice(1,2,None), [2, 3, 4])
请参阅__setitem__
文档以了解其功能。
因此,当您执行my_list[1:2] = my_list[1]
时,您将第一个索引中的内容替换为my_list
的第二个索引,其中第一个索引中存在的内容为my_list
,即[2, 3, 4]
我认为现在我们可以回答为什么你的假设是错误的:
- 将[2,3,4]放入列表中的第二个位置(已经存在的位置)
没有。因为__setitem__
未在索引上调用,而是在您传递的索引的slice
上调用。
- 给尝试将三个值(即2,3,4)放入一个长度为1的容器(即my_list [1:2])时出现“太多值解包”错误。
再次编号因为创建容器的索引范围被替换为新的值集。
答案 2 :(得分:2)
如果目标是切片:参考中的主要表达式是 评估。它应该产生一个可变序列对象(例如列表)。 分配的对象应该是相同类型的序列对象。 接下来,在此范围内评估下限和上限表达式 他们在场;默认值为零和序列的长度。该 边界应该评估为整数。如果任何一个是负的,那么 序列的长度被添加到它。生成的边界被剪切为 介于零和序列的长度之间,包括在内。最后, 要求序列对象用该项替换切片 分配顺序。切片的长度可以与切片的长度不同 分配序列的长度,从而改变了长度 目标序列,如果目标序列允许它。
这种行为在定性上是有意义的,因为当您对列表进行切片时,您会得到一个子列表,因此将其替换为另一个列表不应该添加一定级别的嵌套。允许它更改列表的长度是一种设计选择。您的numpy
示例演示了其他选项。
答案 3 :(得分:1)
您正在做的是slice assignment。
也可以分配切片,这甚至可以改变列表的大小或完全清除它
my_list[1:2] = my_list[1]
这会将my_list
的切片替换为my_list[1]
的内容。
通过在赋值运算符my_list[1:2]
的左侧指定=
,您告诉Python您要使用切片赋值。
my_list[1:2] = my_list[1]
相当于my_list.__setitem__(slice(1, 2, None), my_list[1])
在slice(1,2,无)中,1
已开始,2
已停止,None
为步骤且可选。
答案 4 :(得分:1)
您在这里尝试的是 Slice Assingnment 。在python中,可以将一个可迭代的(在您的情况下为my_list[1]
)分配给另一个可迭代的片(在您的情况下为my_list[0:1]
)。让我们通过一些例子来了解它的真正含义:
>>> l = [1,2,3,4,5]
>>> b = [6,7,8]
>>> l[0:3] = b
>>> l
>>> [6, 7, 8, 4, 5]
所以这里发生的是l
索引的列表0,1,2
的部分是
覆盖元素1,2,3
的内容将替换为列表b
6,7,8
的元素。但是在这种情况下,切片和替换元素的大小恰好相等。
那么当切片大小和可迭代的替换不相等时会发生什么
>>> l = [1,2,3,4,5]
>>> b = [6,7,8]
>>> l[0:4] = b
>>> l
>>> [6,7,8,5]
请注意,此操作不会产生任何错误,相反,它只是复制了整个切片部分可用的任何元素。在这种情况下,切片元素1,2,3,4
替换为6,7,8
在前面的示例中,要替换的iterable较小。如果切片部分较小,会发生什么
>>> l = [1,2,3,4,5]
>>> b = [6,7,8]
>>> l[0:1] = b
>>> l
>>> [6,7,8,2,3,4,5]
现在我们可以看到只有第一个元素被整个可迭代b
替换。
您还可以使用此行为删除列表的特定部分(在某些情况下我觉得这很方便)。
>>> l = [1,2,3,4,5]
>>> l[0:2] = []
>>> l
>>> [3,4,5]
这里非常方便地删除前两个元素。
因此,您的问题中的示例与我上面发布的示例类似,只是在您的情况下还有一个解压缩列表值的附加步骤。每次将列表分配给另一个列表时,都会发生解包列表值。一个简短的例子
>>> l = [[1]]
>>> a = []
>>> a = l[0]
>>> a
>>> [1]
你现在的例子:
#Replace the slice [0:1] with my_list[1] perform unpacking list values as well
>>> my_list[1:2] = my_list[1]
>>> [1,2,3,4,5]
另请注意,只有将iterable分配给切片才能进行切片分配。如果你尝试为一个切片分配一个int或某个不可迭代的东西,python会抛出一个错误。
>>> l = [1,2,3,4,5]
>>> b = [6,7,8]
>>> l[0:1] = b[1]
>>> Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only assign an iterable
这就是为什么在你的情况下my_list[1]
不会引发错误,因为它是可迭代的。
答案 5 :(得分:0)
你正在做的是通过切片插入一个元素。我将按部分解释一切。除了插入之外,它可以解释为在所需范围内切割目标列表后将项添加到列表中。现在详细解释每一行:
my_list[1:2]
这部分就像对Python的说法; “我想从索引1到2之前的索引获取值(切片)(不包括2,我将在稍后的另一个例子中解释)”。之后,为这些值分配值:
my_list[1:2] = my_list[1] #The same as my_list[1:2] = [2,3,4]
既然您知道第一部分的作用,接下来它将在'='运算符的右侧添加项目,以便您可以像这样解释它; “我想从索引1切换到2之前的所有内容(再次排除索引2),然后添加我的列表[2,3,4]”。现在这里有另一个例子,所以我希望你能更好地理解。
problemList = [1, [2, 3, 4], 5]
problemList[1:2] = problemList[1] #The same as problemList[1:2] = [2,3,4]
analogProblemL = [1] + [2,3,4] + [5] #Output : [1,2,3,4,5]
insertList = [12,13,14]
myList = [1, [2, 3, 4], 5,6,7,8,9]
myList[3:6] = insertList
analogFstList = [1,[2,3,4] ,5] + insertList + [9] #Output : [1,[2,3,4],5,12,13,14,9]
myScnList = [1, [2, 3, 4], 5]
myScnList[1:3] = [2,3,4]
analogScnList = [1] + [2,3,4] + [5] #Output : [1,2,3,4,5]
接下来的行就像是一个动画帧,所以它更容易解释:
[1,2,3,4,5] #List before line of code: myList[1:3] = [12,13,14]
[1,|2,3|,4,5] #The moment where you slice the list with: myList[1:3]. Please notice that the characters used '|' are for representing the slice.
[1] + [12,13,14] + [4,5] #After assigning what the slice should be changed for. It's like excracting from the whole list the values [2,3] and changing it for [12,13,14].
[1,12,13,14,4,5] #Final list after running the code.
用于此答案的一些参考文献: http://effbot.org/zone/python-list.htm Understanding Python's slice notation How assignment works with python list slice
希望它对你有用。
答案 6 :(得分:-1)
my_list[1:2] = my_list[1], Its simply a inserting statement, it translate to
我们只是尝试my_list1from my_list [1]和my_list2之间的某个元素。现在它与list.extend(list1)非常相似,只是我们在列表之间插入而不是在最后插入