如何使用变量对 Python 列表进行切片?

How to use variables for slicing Python lists?

我有一份包含六项的无害清单 "mylist"。永远不会空着,永远不会有任何野兽般的物品。

mylist = ['aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff']

我发现有两种方法可以为切片索引列表。对于这个问题,我将它们称为上索引(从0到5)下索引(从-1到-6)。这是一个快速图表(我发布了一张带颜色的照片,被另一个用户替换):

 <<<<|_________mylist[5:?:-1]_____________|

     |___mylist[0:3:1]______|>>>>>>
 ?
(x)   0      1      2      3      4      5     (6)

     aaa    bbb    ccc    ddd    eee    fff

(-7) -6     -5     -4     -3     -2     -1     (y)
                                                ?
             <<<<<<|___mylist[-1:-5:-1]___|

     |______mylist[-6:?:1]________________|>>>>>

为了在列表的开头轻松切片,我可以像这样使用上索引:

>>> mylist[0:3:1]
['aaa', 'bbb', 'ccc']

为了在结尾附近轻松切片,我发现较低的索引很有用,例如:

>>> mylist[-1:-5:-1]
['fff', 'eee', 'ddd', 'ccc']

"easily" 我的意思是例如不考虑我的代码与列表长度的方面。

了解到Python分片是"always holding back"(又名"up to but not including")。我在我的图表中将其显示为 "arrow-heads" 从切片的末尾指向前面的 "next item"(切片的 sense/direction 中的 "ahead")。

对于我的用户,我需要显示列表中的前这么多项目。 (这些是递归搜索、评估和排序 运行 的结果。)因为通常这个列表很长,所以我将它打印 backwards (在控制台中),所以当脚本结束时,最好的 n 结果仍会显示在屏幕上。所以我的步骤是 -1 在这种情况下。

我想使用变量来满足不同用户(和不同屏幕尺寸)的不同需求。 对于调试和某些用户,我希望能够打印所有结果,即向后打印整个列表。我想要这种语法中的内容:

start = 5     # I only need to know "5" for debugging, normally I can use
              # any small number to show a few selected items of mylist

end = x       # this is my main question, see photo

mylist[start:end:-1]

我的问题是,如何在图中写第一个(最上面的)切片,通过使用变量通过使用索引的上层列表 或者换句话说,x(和y的数值是多少在图中?

我不想使用的半解决方案:

mylist[5::-1]       # no variable at all

mylist[5:None:-1]   # does not fit in my normal function for printing

我没有设法在任何简单的变量操作中使用 None,它给我这样的错误:

    end = None - 20 
TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'

而且我还没有设法将 None 转换为任何整数或其他数字。有办法吗?在 Python 土地上可能是一种亵渎...

如果我找不到x的秘密号码,那么我可能需要使用这个:

mylist[-1:-7:-1]  # I want to use the upper index rather

但这种方法涉及检查 mystring 的长度。

end = -1 * (len(mystring)+1)  # extra-explicit as an example
returns  -7

mystring[-1:end:-1]

returns  ['fff', 'eee', 'ddd', 'ccc', 'bbb', 'aaa']  # this is the output I want, just not the method

问你之前我做了什么:
我写了一个测试脚本并尝试猜测 x。我在 Stack Overflow 上搜索并阅读了大量关于切片和变量的内容(比如 ) and online (like https://docs.python.org/3/library/functions.html?highlight=slice#slice),我还搜索了电子书,比如 Introducing Python 和 Learning Python.

请求:
请不要告诉我我想要的是错误的。尽管在我的示例列表中没有索引为 6 的项目,但我可以对 mylist[0:6:1] 进行切片,-7 也是如此。这就是为什么我有这种预感,可能会有 xy 的数字,我可以在我的变量中使用它们。

欢迎您告诉我它不存在或无法按照我希望的方式完成。在后一种情况下,我还要求您提供尽可能接近我的要求的替代方案。

想要更多的背景:
这个问题更多的是关于 "figuring out slicing" 而不是关于使打印输出成为可能。我确实有解决方法,但很想了解更多。

简短的回答是:


如果你不想计算列表的长度,你必须使用None(虽然这是Python中的O(1)操作):

>>> mylist = ['aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff']
>>> mylist[2:None:-1]  # first 3 items backwards (note off-by-one indexing)
['ccc', 'bbb', 'aaa']
>>> mylist[None:None:-1]  # all items backwards
['fff', 'eee', 'ddd', 'ccc', 'bbb', 'aaa']

可以"the whole thing"使用占位符,例如0:

>>> end = 3
>>> mylist[end - 1 if end else None::-1]
['ccc', 'bbb', 'aaa']
>>> end = 0
>>> mylist[end - 1 if end else None::-1]
['fff', 'eee', 'ddd', 'ccc', 'bbb', 'aaa']

你也可以考虑两个步骤,即取你想要的切片然后反转它:

>>> mylist[:3][::-1]
['ccc', 'bbb', 'aaa']

只需设置一个默认值,如果用户更改默认值 (max),则更改您的变量。

>>> mylist = ['aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff']
>>> display_num = len(mylist)
>>> mylist[display_num-1::-1]
['fff', 'eee', 'ddd', 'ccc', 'bbb', 'aaa']

将 display_num 变量更改为您要显示的结果数。

>>> display_num = 4
>>> mylist[display_num-1::-1]
['ddd', 'ccc', 'bbb', 'aaa']

我认为你的选择是 None 或列表的长度。

... 或者只使用 try catch

>>> display_num = None
>>> try:
>>>     mylist[display_num-1::-1]
>>> except TypeError:
>>>     mylist[::-1]

如果我没有正确理解你的问题,你希望 y 这样

mylist[2:y:-1] == ['ccc', 'bbb', 'aaa']

其中 y 必须是整数。

您要查找的 y-len(mylist)-1 或更小的整数。如果你需要一个常量,你可以使用 -sys.maxsize(因为不可能有大于 maxsize 的列表)。


如果我们查看CPython的源代码,我们可以看到list objects internally use the function PySlice_GetIndicesEx. In order to do what you want, PySlice_GetIndicesEx必须设置step = -1start = 2slicelength = 3.

start = 2step = -1 已由您的代码设置。 y 的值是否可以导致 slicelength = 3?让我们看看...

step为负数时,计算slicelength的行为this one:

*slicelength = (*stop-*start+1)/(*step)+1;

从这里我们可以看出,为了slicelength = (stop - start + 1) / step + 1 = 3,我们必须有停止 = -1。但是,the case stop < 0 is treated specially:

if (*stop < 0) *stop += length;
if (*stop < 0) *stop = (*step < 0) ? -1 : 0;

因此,如果我们提供负值 stop,它会增加 len(mylist)。如果 stop 仍然是负数,它被设置为 -1,这是我们需要的值。