在Python中反转列表切片

6

我正在尝试在Python中对列表进行反向切片,但返回一个空列表。但是当我尝试使用整个列表时,它可以正常工作。这里是否有什么遗漏?

l = [1,2,3,4,5,6,7,8]
l[::-1] = [8, 7, 6, 5, 4, 3, 2, 1]     # <<< This worked fine.

l[2:5] = [3, 4, 5]
l[2:5:-1] = []       # <<< Expecting [5,4,3] here.

有什么线索吗?


2
在使用不同的方括号时,l[2:5][::-1] 的功能是有效的。 - user5077528
1
дҪ йңҖиҰҒдҪҝз”ЁиҙҹжӯҘй•ҝ-1иҖҢдёҚжҳҜеҖ’еәҸжқҘиҺ·еҫ—l[4:1:-1]гҖӮ - Padraic Cunningham
@PadraicCunningham 为什么这个不起作用,而 l[2:5:2] 却可以工作,我很好奇。 - EdChum
4
@EdChum,你现在从2开始,每次倒退1个单位尝试到达5,这样做没有意义,要想到达5就不应该从2开始倒退。 - Padraic Cunningham
3
因为你试图从2倒数到5。 - TigerhawkT3
@TigerhawkT3 哦,好的,如果你已经分配了切片,那么它就可以正常工作:p=l[2:] p[::-1]。我原以为索引会变成匿名索引值,所以步进操作只需要起作用。 - EdChum
3个回答

9

语法始终为[开始:结束:步长],因此如果向后移动,则起点需要大于终点。还要记住它包括起点但不包括终点,因此在交换起点和终点后,需要减去1。

l[5:2:-1]= [6, 5, 4]
l[4:1:-1]= [5, 4, 3]

0

切片符号是[start:stop:step]。这意味着“从start开始,然后每次增加step直到达到end”。它类似于以下结构:

counter = 0
stop = 10
step = 1
while counter < stop:
    print(counter)
    counter += step

这将按预期生成09

现在想象一下,如果我们尝试使用您正在使用的值:

counter = 2
stop = 5
step = -1
while counter < stop:
    print(counter)
    counter += step

如果我们实际执行这个程序,它会先打印出2,然后将其加上-1得到1,之后打印出1并将其加上-1得到0,接着会变成-1-2等等,永无止境。你必须手动停止程序才能阻止这个无限循环。
如果你将参数中的 startstop 留空,如在 [:4][::-1] 中所示,这表示序列的开头或结尾,取决于 step 的规定。Python 会根据正数的 step 向前遍历序列, 根据负数的 step 向后遍历(使用 0 作为步长会产生错误)。
>>> l[2::]
[3, 4, 5, 6, 7, 8]
>>> l[2::-1]
[3, 2, 1]
>>> l[:2:]
[1, 2]
>>> l[:2:-1]
[8, 7, 6, 5, 4]

如果您指定了无法工作的startendstep(空的step默认为1),Python将只返回一个空序列。

0

为什么 L[::-1] 返回的是一个反转后的列表,但是 L[2:5:-1] 却返回了空的 [] 列表??

混淆的核心在于错误地假定在切片 [start:stop:step] 中,如果缺少起始值,则始终将其设置为开始,而缺少的停止值则设置为列表的末尾。

这个假设是不正确的,因为在 Python 中,如果您没有明确指定 startstop,Python 将根据 step 的符号以不同的方式替换缺失的 startstop 值,在存在负的 step 值的情况下,将 start 设置为列表的结尾而不是开头。

当您在切片L[start:stop:step]中不指定start和/或stop值(即使用L[::step])时,Python将按以下方式执行:

  • 如果step具有正值,则start将设置为0(并且stop将设置为len(L)
  • 如果step具有负值,则start将设置为len(L)-1。如果未指定stop的值,则无法用切片表示,并且需要将切片定义值转换为range()的参数。
处理未明确指定切片值的不同情况以及允许在切片中使用负值索引的特性,在Python源代码中通过多个if语句进行编码,最终定义了切片的行为。因此,要完全理解Python的切片,您必须了解它们是如何编码的。由于不存在一个唯一合理的直接规则来编码切片行为,所以设计切片的决策集并不总是直接符合人们的直观期望。

让我们提供一些代码来证明上面的内容是正确的,并通过其他方式解释与上述已经说明的相同(请参见代码中的注释)。以下代码使用Python的assert语句来检查给定的比较是否显示正确的切片值,并在Python中使用slice对象可用的.indices()方法,为range()返回所需的表示切片对象的列表索引的参数:

L = [1,2,3,4,5,6]
assert L[ : :  ]    == [1,2,3,4,5,6] # << OK. No AssertionError.
assert L[ : :-1]    == L[len(L)-1:-len(L)-1:-1] == [6,5,4,3,2,1]
assert L[ : :-1]    == [6,5,4,3,2,1] # << OK. No AssertionError.
assert L[2:5:  ]    == [3,4,5]
# ===
assert L[2: :-1]    == [3,2,1]
# ^-- because with -1 step and decreasing i -= 1 starting with 0  
# ^-- the condition (2+i > -1) for list index gives [3,2,1]
assert slice(2,None,-1).indices(len(L)) == (2,-1,-1)  
# ^-- and because the None becomes -1 ( for use in range() ) 
# ===
assert L[ :5:-1]    == []
# ^-- because with -1 step and decreasing i -= 1 starting with 0  
# ^-- no list item will meet the condition (2+i > 5) for its index  
assert slice(None,5,-1).indices(len(L)) == (5,5,-1)  
# ^-- and because the None becomes 5 ( for use in range() ) 
# ===
assert L[2:5:-1]    == [] 
# ^-- because with -1 step and decreasing i -= 1 starting with 0  
# ^-- no list item will meet the condition (2+i > 5) for its index  
assert slice(2,5,-1).indices(len(L)) == (2,5,-1)  
# ^-- and because range(2,5,-1) does not return any values 
# ^-- and because you are starting at 2 and stepping -1 trying to get 
#     to 5 ( you can't count backwards from 2 to 5 ) 
# ===
assert L[2:5][::-1] == [5,4,3] # it works in different square brackets 
assert L[4:1:-1]    == [5,4,3] # '-1' is not reversing, it is stepping

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接