情况如下:我有一个简单的列表
my_list = list(range(10)) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
我可以对它执行两个切片,并打印结果如下:
print(my_list[9:1:-1][::-1]) # [2, 3, 4, 5, 6, 7, 8, 9]
但这当然可以用单个切片完成:
print(my_list[2:]) # [2, 3, 4, 5, 6, 7, 8, 9]
是否有一个很好的理由去做我在第二行代码中所展示的事情,即对同一个列表进行两次切片?这看起来非常不python,但也许有一个用例,切片参数是由变量提供的。为什么存在像我上面所做的那样对同一个列表进行双重切片的功能?
我想不出一个"好的理由";要切片两次,但想要推回"为什么存在对同一列表进行双重切片的功能…?"因为你的不是对同一个列表切片两次。初始的my_list[9:1:-1]
创建一个全新的列表,然后[::-1]
对这个列表进行切片。该语言根本没有做任何事情来迎合这一点:[::-1]
适用于任何可切片的对象,而my_list[9:1:-1]
只是创建可切片对象的许多方法之一。
所以你的问题类似于问"为什么存在对同一个整数加两次的功能?"关于代码i = j + 5 + 8
。: -)
一个例子这在某种程度上是人为的,但如果它在现实生活中出现在非时间临界部分,我会毫不犹豫地使用双切片。
假设您想要获得序列中每一个第98个元素,但也要以相反的顺序。所以,例如,
>>> xs = list(range(1000))
>>> xs[::98][::-1]
[980, 882, 784, 686, 588, 490, 392, 294, 196, 98, 0]
这个可以用一个切片得到,但我敢打赌大多数人会努力拼写正确:
>>> xs[980::-98]
[980, 882, 784, 686, 588, 490, 392, 294, 196, 98, 0]
>>>
请注意,您必须自己计算980,否则您将不知道反转切片应该从哪里开始。并且必须省略第二个slice参数(或者在那里显式地使用None
)。
0
不工作,因为切片在到达第二个索引之前停止:
>>> xs[980:0:-98]
[980, 882, 784, 686, 588, 490, 392, 294, 196, 98]
请注意,后面的0
丢失了。-1也不行,尽管
>>> list(range(980, -1, -98))
[980, 882, 784, 686, 588, 490, 392, 294, 196, 98, 0]
工作好。但那是range()
。在切片上下文中,-1
表示"序列的最后一个元素",而不是第一个元素。
>>> xs[980:-1:-98]
[]
从元素980返回到元素999,当然会得到一个空列表。
在一般情况下获得正确的反向切片是非常棘手的。
我以前遇到过这样的问题,我想从一个端点依赖于用户输入的列表中获得一个反向切片。那么,一个简单的例子:
start = int(input('low index for slice (inclusive): '))
end = int(input('high index for slice (inclusive): '))
my_slice = original[end:start-1:-1]
哎呀:当为start
提供0
时,索引变成了-1
,这导致它不能按预期工作。我们可以对这种情况进行特殊处理,用None
代替-1
;但是"特殊情况"还不足以打破规则,而且"简单比复杂好"。直接写original[start:end+1][::-1]
要好得多,也更容易理解。
当你这样做的时候-
print(my_list[9:1:-1][::-1]) # [2, 3, 4, 5, 6, 7, 8, 9]
然后你首先创建一个新列表my_list[9:1:-1],然后你通过创建另一个新列表my_list[9:1:-1][::-1]来分割这个新列表。这将占用更多的空间。
但是当你这样做时-
print(my_list[2:]) # [2, 3, 4, 5, 6, 7, 8, 9]
你只创建一个新列表一次,这占用更少的空间