【问题标题】:理解切片符号
【发布时间】:2025-02-23 15:40:01
【问题描述】:

我需要对 Python 的切片表示法进行很好的解释(参考文献是加分项)。

对我来说,这个符号需要一点了解。

它看起来非常强大,但我还没有完全理解它。

【问题讨论】:

    标签: python list slice iterable


    【解决方案1】:

    其实很简单:

    a[start:stop]  # items start through stop-1
    a[start:]      # items start through the rest of the array
    a[:stop]       # items from the beginning through stop-1
    a[:]           # a copy of the whole array
    

    还有step 值,可以与上述任何一种一起使用:

    a[start:stop:step] # start through not past stop, by step
    

    要记住的关键点是:stop 值表示所选切片中不是的第一个值。所以,stopstart 之间的区别在于选择的元素数量(如果 step 为 1,则默认为 1)。

    另一个特点是startstop 可能是一个负数 数,这意味着它从数组的末尾而不是开头开始计数。所以:

    a[-1]    # last item in the array
    a[-2:]   # last two items in the array
    a[:-2]   # everything except the last two items
    

    同样,step 可能是负数:

    a[::-1]    # all items in the array, reversed
    a[1::-1]   # the first two items, reversed
    a[:-3:-1]  # the last two items, reversed
    a[-3::-1]  # everything except the last two items, reversed
    

    如果项目比你要求的少,Python 对程序员很友好。例如,如果您要求 a[:-2] 并且 a 仅包含一个元素,您会得到一个空列表而不是错误。有时您更喜欢错误,因此您必须意识到这可能会发生。

    slice() 对象的关系

    切片运算符[]实际上是在上面的代码中使用slice()对象使用:表示法(仅在[]内有效),即:

    a[start:stop:step]
    

    相当于:

    a[slice(start, stop, step)]
    

    根据参数的数量,Slice 对象的行为也略有不同,类似于range(),即同时支持slice(stop)slice(start, stop[, step])。 要跳过指定给定参数,可以使用None,例如a[start:] 等价于a[slice(start, None)]a[::-1] 等价于a[slice(None, None, -1)]

    虽然基于: 的表示法对于简单的切片非常有用,但显式使用slice() 对象可以简化切片的编程生成。

    【讨论】:

    • 切片内置类型返回一个副本,但这不是通用的。值得注意的是,slicing NumPy arrays 返回一个与原始视图共享内存的视图。
    • 这是一个漂亮的答案,有投票来证明这一点,但它遗漏了一件事:您可以用None 替换任何空白空间。例如[None:None] 制作一个完整的副本。当您需要使用变量指定范围的结尾并需要包含最后一项时,这很有用。
    • 请注意,与通常的 Python 切片(见上文)相反,在 Pandas Dataframes 中,开始和结束都包含在索引中。如需更多信息,请参阅Pandas indexing documentation
    • 真正让我恼火的是python说当你不设置开始和结束时,它们默认为0和序列的长度。因此,理论上,当您使用“abcdef”[::-1] 时,它应该转换为“abcdef”[0:6:-1],但这两个表达式不会得到相同的输出。我觉得自语言创建以来,python 文档中缺少一些东西。
    • 而且我知道 "abcdef"[::-1] 被转换为 "abcdef"[6:-7:-1],所以,最好的解释方法是:让 len 是序列的长度。 如果 step 为正,start 和 end 的默认值为 0 和 len否则,如果 step 为负数,start 和 end 的默认值为 len 和 -len - 1。
    【解决方案2】:

    Python tutorial 谈论它(向下滚动一点,直到您到达关于切片的部分)。

    ASCII 艺术图也有助于记住切片的工作原理:

     +---+---+---+---+---+---+
     | P | y | t | h | o | n |
     +---+---+---+---+---+---+
     0   1   2   3   4   5   6
    -6  -5  -4  -3  -2  -1
    

    记住切片如何工作的一种方法是将索引视为指向 个字符之间,第一个字符的左边缘编号为 0。然后是字符串的最后一个字符的右边缘n 个字符的索引为 n

    【讨论】:

    • 此建议适用于正步幅,但不适用于负步幅。从图中,我预计a[-4,-6,-1]yP,但它是ty。始终有效的方法是考虑字符或插槽并将索引用作半开区间——如果是正步幅则右开,如果步幅负则左开。
    • 但是没有办法从头开始折叠到一个空集(就像x[:0]从头开始时所做的那样),所以你必须特殊情况下的小数组。 ://
    • @aguadopd 你说得对。解决方案是将索引向右移动,在字符下方居中,并注意始终排除停止。请参阅下面的另一个回复。
    • 我的评论的附录:用下图查看我的答案:*.com/a/56332104/2343869
    【解决方案3】:

    枚举语法允许的可能性:

    >>> seq[:]                # [seq[0],   seq[1],          ..., seq[-1]    ]
    >>> seq[low:]             # [seq[low], seq[low+1],      ..., seq[-1]    ]
    >>> seq[:high]            # [seq[0],   seq[1],          ..., seq[high-1]]
    >>> seq[low:high]         # [seq[low], seq[low+1],      ..., seq[high-1]]
    >>> seq[::stride]         # [seq[0],   seq[stride],     ..., seq[-1]    ]
    >>> seq[low::stride]      # [seq[low], seq[low+stride], ..., seq[-1]    ]
    >>> seq[:high:stride]     # [seq[0],   seq[stride],     ..., seq[high-1]]
    >>> seq[low:high:stride]  # [seq[low], seq[low+stride], ..., seq[high-1]]
    

    当然,如果(high-low)%stride != 0,那么终点会比high-1低一点。

    如果stride 为负数,由于我们正在倒计时,因此排序会发生一些变化:

    >>> seq[::-stride]        # [seq[-1],   seq[-1-stride],   ..., seq[0]    ]
    >>> seq[high::-stride]    # [seq[high], seq[high-stride], ..., seq[0]    ]
    >>> seq[:low:-stride]     # [seq[-1],   seq[-1-stride],   ..., seq[low+1]]
    >>> seq[high:low:-stride] # [seq[high], seq[high-stride], ..., seq[low+1]]
    

    扩展切片(带有逗号和省略号)主要仅用于特殊数据结构(如 NumPy);基本序列不支持它们。

    >>> class slicee:
    ...     def __getitem__(self, item):
    ...         return repr(item)
    ...
    >>> slicee()[0, 1:2, ::5, ...]
    '(0, slice(1, 2, None), slice(None, None, 5), Ellipsis)'
    

    【讨论】:

    • 实际上还有一些东西遗漏了,例如如果我输入 'apple'[4:-4:-1] 我得到 'elp',python 可能会将 -4 转换为 1?
    • 请注意,反引号已被弃用,取而代之的是 repr
    • @liyuan 实现__getitem__的类型是;你的例子相当于apple[slice(4, -4, -1)]
    • 前两张表是纯金的。
    【解决方案4】:

    上面的答案没有讨论切片分配。要理解切片分配,在 ASCII 艺术中添加另一个概念会很有帮助:

                    +---+---+---+---+---+---+
                    | P | y | t | h | o | n |
                    +---+---+---+---+---+---+
    Slice position: 0   1   2   3   4   5   6
    Index position:   0   1   2   3   4   5
    
    >>> p = ['P','y','t','h','o','n']
    # Why the two sets of numbers:
    # indexing gives items, not lists
    >>> p[0]
     'P'
    >>> p[5]
     'n'
    
    # Slicing gives lists
    >>> p[0:1]
     ['P']
    >>> p[0:2]
     ['P','y']
    

    一种启发式方法是,对于从零到 n 的切片,认为:“零是开头,从开头开始并在列表中取 n 个项目”。

    >>> p[5] # the last of six items, indexed from zero
     'n'
    >>> p[0:5] # does NOT include the last item!
     ['P','y','t','h','o']
    >>> p[0:6] # not p[0:5]!!!
     ['P','y','t','h','o','n']
    

    另一个启发式是,“对于任何切片,用零替换开头,应用前一个启发式来获取列表的末尾,然后计算第一个数字以从开头切掉项目”

    >>> p[0:4] # Start at the beginning and count out 4 items
     ['P','y','t','h']
    >>> p[1:4] # Take one item off the front
     ['y','t','h']
    >>> p[2:4] # Take two items off the front
     ['t','h']
    # etc.
    

    切片赋值的第一条规则是,由于切片返回一个列表,切片赋值需要一个列表(或其他可迭代的):

    >>> p[2:3]
     ['t']
    >>> p[2:3] = ['T']
    >>> p
     ['P','y','T','h','o','n']
    >>> p[2:3] = 't'
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: can only assign an iterable
    

    切片分配的第二条规则,您也可以在上面看到,列表的任何部分由切片索引返回,这与切片分配更改的部分相同:

    >>> p[2:4]
     ['T','h']
    >>> p[2:4] = ['t','r']
    >>> p
     ['P','y','t','r','o','n']
    

    切片分配的第三条规则是,分配的列表(可迭代)不必具有相同的长度;索引切片被简单地切掉并被分配的任何内容全部替换:

    >>> p = ['P','y','t','h','o','n'] # Start over
    >>> p[2:4] = ['s','p','a','m']
    >>> p
     ['P','y','s','p','a','m','o','n']
    

    要习惯的最棘手的部分是分配给空切片。使用启发式 1 和 2 很容易让您了解索引一个空切片:

    >>> p = ['P','y','t','h','o','n']
    >>> p[0:4]
     ['P','y','t','h']
    >>> p[1:4]
     ['y','t','h']
    >>> p[2:4]
     ['t','h']
    >>> p[3:4]
     ['h']
    >>> p[4:4]
     []
    

    一旦你看到了,对空切片的切片分配也很有意义:

    >>> p = ['P','y','t','h','o','n']
    >>> p[2:4] = ['x','y'] # Assigned list is same length as slice
    >>> p
     ['P','y','x','y','o','n'] # Result is same length
    >>> p = ['P','y','t','h','o','n']
    >>> p[3:4] = ['x','y'] # Assigned list is longer than slice
    >>> p
     ['P','y','t','x','y','o','n'] # The result is longer
    >>> p = ['P','y','t','h','o','n']
    >>> p[4:4] = ['x','y']
    >>> p
     ['P','y','t','h','x','y','o','n'] # The result is longer still
    

    请注意,由于我们没有更改切片的第二个数字 (4),因此即使我们分配给空切片,插入的项目也总是与“o”堆叠在一起。所以空切片分配的位置是非空切片分配位置的逻辑扩展。

    稍微备份一下,当你继续我们的计算切片开始的队列时会发生什么?

    >>> p = ['P','y','t','h','o','n']
    >>> p[0:4]
     ['P','y','t','h']
    >>> p[1:4]
     ['y','t','h']
    >>> p[2:4]
     ['t','h']
    >>> p[3:4]
     ['h']
    >>> p[4:4]
     []
    >>> p[5:4]
     []
    >>> p[6:4]
     []
    

    使用切片,一旦你完成,你就完成了;它不会开始向后切片。在 Python 中,除非您使用负数明确要求它们,否则您不会获得负跨度。

    >>> p[5:3:-1]
     ['n','o']
    

    “一旦你完成了,你就完成了”规则有一些奇怪的后果:

    >>> p[4:4]
     []
    >>> p[5:4]
     []
    >>> p[6:4]
     []
    >>> p[6]
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    IndexError: list index out of range
    

    实际上,与索引相比,Python 切片具有奇异的防错性:

    >>> p[100:200]
     []
    >>> p[int(2e99):int(1e99)]
     []
    

    这有时会派上用场,但也可能导致一些奇怪的行为:

    >>> p
     ['P', 'y', 't', 'h', 'o', 'n']
    >>> p[int(2e99):int(1e99)] = ['p','o','w','e','r']
    >>> p
     ['P', 'y', 't', 'h', 'o', 'n', 'p', 'o', 'w', 'e', 'r']
    

    根据您的应用程序,这可能...也可能不是...是您所希望的!


    以下是我原始答案的文字。对很多人有用,所以不想删了。

    >>> r=[1,2,3,4]
    >>> r[1:1]
    []
    >>> r[1:1]=[9,8]
    >>> r
    [1, 9, 8, 2, 3, 4]
    >>> r[1:1]=['blah']
    >>> r
    [1, 'blah', 9, 8, 2, 3, 4]
    

    这也可以澄清切片和索引之间的区别。

    【讨论】:

    • 很好的解释。但是切片背后的逻辑非常不直观。
    【解决方案5】:

    解释 Python 的切片表示法

    简而言之,下标表示法 (subscriptable[subscriptarg]) 中的冒号 (:) 构成切片表示法 - 它具有可选参数 startstopstep

    sliceable[start:stop:step]
    

    Python 切片是一种有条不紊地访问部分数据的快速计算方法。在我看来,即使是一名中级 Python 程序员,也是必须熟悉的语言的一个方面。

    重要定义

    首先,让我们定义几个术语:

    start:切片的开始索引,除非与stop相同,否则会包含该索引处的元素,默认为0,即第一个索引.如果为负数,则表示从末尾开始n 项。

    stop:切片的结束索引,它确实包含该索引处的元素,默认为被切片序列的长度,即最多包括结尾。

    步长:索引增加的量,默认为 1。如果它是负数,你正在反向切片迭代。

    索引的工作原理

    您可以制作任何这些正数或负数。正数的含义很简单,但是对于负数,就像 Python 中的索引一样,startstop 从末尾倒数,step,你只需减少你的索引。这个例子是from the documentation's tutorial,但我稍微修改了它以指示每个索引引用序列中的哪个项目:

     +---+---+---+---+---+---+
     | P | y | t | h | o | n |
     +---+---+---+---+---+---+
       0   1   2   3   4   5 
      -6  -5  -4  -3  -2  -1
    

    切片的工作原理

    要将切片表示法与支持它的序列一起使用,您必须在序列后面的方括号中至少包含一个冒号(实际上是implement the __getitem__ method of the sequence, according to the Python data model。)

    切片符号的工作方式如下:

    sequence[start:stop:step]
    

    记得 startstopstep 有默认值,因此要访问默认值,只需省略参数即可。

    从列表(或任何其他支持它的序列,如字符串)中获取最后九个元素的切片表示法如下所示:

    my_list[-9:]
    

    当我看到这个时,我将括号中的部分读作“从末尾到末尾的第 9 个”。 (其实我在心里把它缩写成“-9, on”)

    解释:

    完整的符号是

    my_list[-9:None:None]
    

    并替换默认值(实际上当step 为负数时,stop 的默认值是-len(my_list) - 1,所以None 停止实际上只是意味着它会进入任何结束步骤):

    my_list[-9:len(my_list):1]
    

    冒号:,告诉 Python 你给了它一个切片而不是常规索引。这就是为什么在 Python 2 中制作列表的浅拷贝的惯用方式是

    list_copy = sequence[:]
    

    清除它们是:

    del my_list[:]
    

    (Python 3 获得了 list.copylist.clear 方法。)

    step 为负数时,startstop 的默认值发生变化

    默认情况下,当step参数为空(或None)时,分配给+1

    但是你可以传入一个负整数,列表(或大多数其他标准的slicables)将从尾到头进行切片。

    因此,负切片将更改 startstop 的默认值!

    在源代码中确认这一点

    我喜欢鼓励用户阅读源代码和文档。 source code for slice objects and this logic is found here。首先我们判断step是否为负:

     step_is_negative = step_sign < 0;
    

    如果是这样,下限是-1,这意味着我们一直切到并包括开头,上限是长度减1,这意味着我们从结尾开始。 (请注意,-1 的语义与 -1 的语义不同,用户可以在 Python 中传递指示最后一项的索引。)

    if (step_is_negative) {
        lower = PyLong_FromLong(-1L);
        if (lower == NULL)
            goto error;
    
        upper = PyNumber_Add(length, lower);
        if (upper == NULL)
            goto error;
    }
    

    否则step 为正数,下限为零,上限(我们向上但不包括)切片列表的长度。

    else {
        lower = _PyLong_Zero;
        Py_INCREF(lower);
        upper = length;
        Py_INCREF(upper);
    }
    

    然后,我们可能需要为startstop 应用默认值 - 当step 为负数时,start 的默认值被计算为上限:

    if (self->start == Py_None) {
        start = step_is_negative ? upper : lower;
        Py_INCREF(start);
    }
    

    stop,下限:

    if (self->stop == Py_None) {
        stop = step_is_negative ? lower : upper;
        Py_INCREF(stop);
    }
    

    给你的切片一个描述性的名字!

    您可能会发现将形成切片与将切片传递给list.__getitem__ 方法(that's what the square brackets do) 分开很有用。即使您不熟悉它,它也可以使您的代码更具可读性,以便可能需要阅读您的代码的其他人更容易理解您在做什么。

    但是,您不能只将一些用冒号分隔的整数分配给变量。您需要使用切片对象:

    last_nine_slice = slice(-9, None)
    

    第二个参数None 是必需的,因此第一个参数被解释为start 参数otherwise it would be the stop argument

    然后您可以将切片对象传递给您的序列:

    >>> list(range(100))[last_nine_slice]
    [91, 92, 93, 94, 95, 96, 97, 98, 99]
    

    有趣的是范围也需要切片:

    >>> range(100)[last_nine_slice]
    range(91, 100)
    

    内存注意事项:

    由于 Python 列表切片会在内存中创建新对象,因此需要注意的另一个重要函数是 itertools.islice。通常,您需要迭代切片,而不仅仅是在内存中静态创建它。 islice 非常适合这个。需要注意的是,它不支持对 startstopstep 的否定参数,因此如果这是一个问题,您可能需要提前计算索引或反转迭代。

    length = 100
    last_nine_iter = itertools.islice(list(range(length)), length-9, None, 1)
    list_last_nine = list(last_nine_iter)
    

    现在:

    >>> list_last_nine
    [91, 92, 93, 94, 95, 96, 97, 98, 99]
    

    列表切片复制的事实是列表本身的一个特性。如果您要对 Pandas DataFrame 等高级对象进行切片,它可能会返回原始视图,而不是副本。

    【讨论】:

    • 我喜欢命名切片的想法。我建议(start:stop) 表示法具有误导性,(start_at:stop_before) 表示法可能会阻止我首先搜索此问答。
    • @WinEunuuchs2Unix 这是很好的反馈 - 这是标准的 Python 行为,但可以通过这种方式更清晰,所以我会考虑更新我的材料以包含这种语义。
    【解决方案6】:

    当我第一次看到切片语法时,有几件事对我来说并不是很明显:

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

    反转序列的简单方法!

    如果你出于某种原因想要倒序中的每一秒:

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

    【讨论】:

      【解决方案7】:

      在 Python 2.7 中

      在 Python 中切片

      [a:b:c]
      
      len = length of string, tuple or list
      
      c -- default is +1. The sign of c indicates forward or backward, absolute value of c indicates steps. Default is forward with step size 1. Positive means forward, negative means backward.
      
      a --  When c is positive or blank, default is 0. When c is negative, default is -1.
      
      b --  When c is positive or blank, default is len. When c is negative, default is -(len+1).
      

      了解索引分配非常重要。

      In forward direction, starts at 0 and ends at len-1
      
      In backward direction, starts at -1 and ends at -len
      

      当你说 [a:b:c] 时,你说的是根据 c 的符号(向前或向后),从 a 开始到 b 结束(不包括第 b 个索引处的元素)。使用上面的索引规则,记住你只会找到这个范围内的元素:

      -len, -len+1, -len+2, ..., 0, 1, 2,3,4 , len -1
      

      但是这个范围在两个方向上无限延续:

      ...,-len -2 ,-len-1,-len, -len+1, -len+2, ..., 0, 1, 2,3,4 , len -1, len, len +1, len+2 , ....
      

      例如:

                   0    1    2   3    4   5   6   7   8   9   10   11
                   a    s    t   r    i   n   g
          -9  -8  -7   -6   -5  -4   -3  -2  -1
      

      如果您选择的 a、b 和 c 允许在使用上述 a、b、c 的规则进行遍历时与上述范围重叠,您将获得一个包含元素的列表(在遍历期间被触摸),或者您将获得一个空的列表。

      最后一件事:如果 a 和 b 相等,那么你也会得到一个空列表:

      >>> l1
      [2, 3, 4]
      
      >>> l1[:]
      [2, 3, 4]
      
      >>> l1[::-1] # a default is -1 , b default is -(len+1)
      [4, 3, 2]
      
      >>> l1[:-4:-1] # a default is -1
      [4, 3, 2]
      
      >>> l1[:-3:-1] # a default is -1
      [4, 3]
      
      >>> l1[::] # c default is +1, so a default is 0, b default is len
      [2, 3, 4]
      
      >>> l1[::-1] # c is -1 , so a default is -1 and b default is -(len+1)
      [4, 3, 2]
      
      
      >>> l1[-100:-200:-1] # Interesting
      []
      
      >>> l1[-1:-200:-1] # Interesting
      [4, 3, 2]
      
      
      >>> l1[-1:-1:1]
      []
      
      
      >>> l1[-1:5:1] # Interesting
      [4]
      
      
      >>> l1[1:-7:1]
      []
      
      >>> l1[1:-7:-1] # Interesting
      [3, 2]
      
      >>> l1[:-2:-2] # a default is -1, stop(b) at -2 , step(c) by 2 in reverse direction
      [4]
      

      【讨论】:

      • 另一个有趣的例子:a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]; a[:-2:-2] 导致[9]
      【解决方案8】:

      http://wiki.python.org/moin/MovingToPythonFromOtherLanguages找到这张很棒的桌子

      Python indexes and slices for a six-element list.
      Indexes enumerate the elements, slices enumerate the spaces between the elements.
      
      Index from rear:    -6  -5  -4  -3  -2  -1      a=[0,1,2,3,4,5]    a[1:]==[1,2,3,4,5]
      Index from front:    0   1   2   3   4   5      len(a)==6          a[:5]==[0,1,2,3,4]
                         +---+---+---+---+---+---+    a[0]==0            a[:-2]==[0,1,2,3]
                         | a | b | c | d | e | f |    a[5]==5            a[1:2]==[1]
                         +---+---+---+---+---+---+    a[-1]==5           a[1:-1]==[1,2,3,4]
      Slice from front:  :   1   2   3   4   5   :    a[-2]==4
      Slice from rear:   :  -5  -4  -3  -2  -1   :
                                                      b=a[:]
                                                      b==[0,1,2,3,4,5] (shallow copy of a)

      【讨论】:

        【解决方案9】:

        用了一点之后才发现,最简单的描述就是和for循环中的参数一模一样……

        (from:to:step)
        

        其中任何一个都是可选的:

        (:to:step)
        (from::step)
        (from:to)
        

        那么负索引只需要你把字符串的长度加上负索引就可以理解了。

        无论如何这对我有用...

        【讨论】:

          【解决方案10】:

          我发现记住它的工作原理更容易,然后我可以找出任何特定的开始/停止/步骤组合。

          先了解range()很有启发性:

          def range(start=0, stop, step=1):  # Illegal syntax, but that's the effect
              i = start
              while (i < stop if step > 0 else i > stop):
                  yield i
                  i += step
          

          start 开始,以step 递增,不要到达stop。很简单。

          关于负步要记住的是,stop 始终是排除端,无论它是更高还是更低。如果您希望以相反的顺序进行相同的切片,则单独进行反转要干净得多:例如'abcde'[1:-2][::-1] 从左边切掉一个字符,从右边切掉两个,然后反转。 (另见reversed()。)

          序列切片是一样的,只是先对负索引进行归一化,而且永远不能超出序列:

          TODO:下面的代码在 abs(step)>1 时出现“永远不要超出序列”的错误;我认为我将其修补为正确的,但很难理解。

          def this_is_how_slicing_works(seq, start=None, stop=None, step=1):
              if start is None:
                  start = (0 if step > 0 else len(seq)-1)
              elif start < 0:
                  start += len(seq)
              if not 0 <= start < len(seq):  # clip if still outside bounds
                  start = (0 if step > 0 else len(seq)-1)
              if stop is None:
                  stop = (len(seq) if step > 0 else -1)  # really -1, not last element
              elif stop < 0:
                  stop += len(seq)
              for i in range(start, stop, step):
                  if 0 <= i < len(seq):
                      yield seq[i]
          

          不要担心 is None 的详细信息 - 请记住,省略 start 和/或 stop 总是会为您提供完整的序列。

          首先规范化负索引允许从末尾独立计算开始和/或停止:'abcde'[1:-2] == 'abcde'[1:3] == 'bc' 尽管range(1,-2) == []。 规范化有时被认为是“模长度”,但请注意它只添加一次长度:例如'abcde'[-53:42] 只是整个字符串。

          【讨论】:

          • this_is_how_slicing_works 与 python 切片不同。例如。 [0, 1, 2][-5:3:3] 在 python 中会得到 [0],但 list(this_is_how_slicing_works([0, 1, 2], -5, 3, 3)) 会得到 [1]。
          • @Eastsun 哎呀,你是对的!一个更清晰的案例:range(4)[-200:200:3] == [0, 3]list(this_is_how_slicing_works([0, 1, 2, 3], -200, 200, 3)) == [2]。我的if 0 &lt;= i &lt; len(seq): 试图简单地实现“永远不要超出序列”,但对于 step>1 是错误的。我将在今天晚些时候重写它(通过测试)。
          【解决方案11】:

          我自己使用“元素之间的索引点”的方法来思考它,但有时可以帮助其他人理解它的一种描述方式是这样的:

          mylist[X:Y]
          

          X 是您想要的第一个元素的索引。
          Y 是您想要的第一个元素的索引。

          【讨论】:

            【解决方案12】:
            Index:
                  ------------>
              0   1   2   3   4
            +---+---+---+---+---+
            | a | b | c | d | e |
            +---+---+---+---+---+
              0  -4  -3  -2  -1
                  <------------
            
            Slice:
                <---------------|
            |--------------->
            :   1   2   3   4   :
            +---+---+---+---+---+
            | a | b | c | d | e |
            +---+---+---+---+---+
            :  -4  -3  -2  -1   :
            |--------------->
                <---------------|
            

            我希望这将帮助您在 Python 中对列表进行建模。

            参考:http://wiki.python.org/moin/MovingToPythonFromOtherLanguages

            【讨论】:

              【解决方案13】:

              这就是我向新手教授切片的方式:

              了解索引和切片的区别:

              Wiki Python 有这张惊人的图片,它清楚地区分了索引和切片。

              这是一个包含六个元素的列表。为了更好地理解切片,将该列表视为一组放置在一起的六个框。每个盒子里都有一个字母。

              索引就像处理盒子的内容。您可以检查任何框的内容。但是您不能一次检查多个框的内容。你甚至可以替换盒子里的东西。但是你不能在一个盒子里放两个球或一次更换两个球。

              In [122]: alpha = ['a', 'b', 'c', 'd', 'e', 'f']
              
              In [123]: alpha
              Out[123]: ['a', 'b', 'c', 'd', 'e', 'f']
              
              In [124]: alpha[0]
              Out[124]: 'a'
              
              In [127]: alpha[0] = 'A'
              
              In [128]: alpha
              Out[128]: ['A', 'b', 'c', 'd', 'e', 'f']
              
              In [129]: alpha[0,1]
              ---------------------------------------------------------------------------
              TypeError                                 Traceback (most recent call last)
              <ipython-input-129-c7eb16585371> in <module>()
              ----> 1 alpha[0,1]
              
              TypeError: list indices must be integers, not tuple
              

              切片就像处理盒子本身。您可以拿起第一个盒子并将其放在另一张桌子上。拿起盒子,你只需要知道盒子的开始和结束的位置。

              您甚至可以选择前三个框或后两个框或 1 到 4 之间的所有框。因此,如果您知道开头和结尾,则可以选择任意一组框。这些位置称为开始位置和停止位置。

              有趣的是,您可以一次更换多个盒子。您也可以将多个盒子放在任何您喜欢的地方。

              In [130]: alpha[0:1]
              Out[130]: ['A']
              
              In [131]: alpha[0:1] = 'a'
              
              In [132]: alpha
              Out[132]: ['a', 'b', 'c', 'd', 'e', 'f']
              
              In [133]: alpha[0:2] = ['A', 'B']
              
              In [134]: alpha
              Out[134]: ['A', 'B', 'c', 'd', 'e', 'f']
              
              In [135]: alpha[2:2] = ['x', 'xx']
              
              In [136]: alpha
              Out[136]: ['A', 'B', 'x', 'xx', 'c', 'd', 'e', 'f']
              

              步长切片:

              到目前为止,您已经连续挑选了箱子。但有时您需要谨慎选择。例如,您可以每隔一个箱子捡起一次。你甚至可以从最后拿起每三个盒子。这个值称为步长。这代表了您连续拾取之间的差距。如果您从头到尾挑选盒子,则步长应该是正数,反之亦然。

              In [137]: alpha = ['a', 'b', 'c', 'd', 'e', 'f']
              
              In [142]: alpha[1:5:2]
              Out[142]: ['b', 'd']
              
              In [143]: alpha[-1:-5:-2]
              Out[143]: ['f', 'd']
              
              In [144]: alpha[1:5:-2]
              Out[144]: []
              
              In [145]: alpha[-1:-5:2]
              Out[145]: []
              

              Python 如何找出丢失的参数:

              切片时,如果你遗漏了任何参数,Python 会尝试自动找出它。

              如果您查看CPython 的源代码,您会发现一个名为 PySlice_GetIndicesEx() 的函数,它为任何给定参数计算出切片的索引。这是 Python 中的逻辑等效代码。

              此函数采用 Python 对象和可选参数进行切片,并返回请求切片的开始、停止、步长和切片长度。

              def py_slice_get_indices_ex(obj, start=None, stop=None, step=None):
              
                  length = len(obj)
              
                  if step is None:
                      step = 1
                  if step == 0:
                      raise Exception("Step cannot be zero.")
              
                  if start is None:
                      start = 0 if step > 0 else length - 1
                  else:
                      if start < 0:
                          start += length
                      if start < 0:
                          start = 0 if step > 0 else -1
                      if start >= length:
                          start = length if step > 0 else length - 1
              
                  if stop is None:
                      stop = length if step > 0 else -1
                  else:
                      if stop < 0:
                          stop += length
                      if stop < 0:
                          stop = 0 if step > 0 else -1
                      if stop >= length:
                          stop = length if step > 0 else length - 1
              
                  if (step < 0 and stop >= start) or (step > 0 and start >= stop):
                      slice_length = 0
                  elif step < 0:
                      slice_length = (stop - start + 1)/(step) + 1
                  else:
                      slice_length = (stop - start - 1)/(step) + 1
              
                  return (start, stop, step, slice_length)
              

              这是切片背后的智能。由于 Python 有一个名为 slice 的内置函数,因此您可以传递一些参数并检查它计算缺失参数的智能程度。

              In [21]: alpha = ['a', 'b', 'c', 'd', 'e', 'f']
              
              In [22]: s = slice(None, None, None)
              
              In [23]: s
              Out[23]: slice(None, None, None)
              
              In [24]: s.indices(len(alpha))
              Out[24]: (0, 6, 1)
              
              In [25]: range(*s.indices(len(alpha)))
              Out[25]: [0, 1, 2, 3, 4, 5]
              
              In [26]: s = slice(None, None, -1)
              
              In [27]: range(*s.indices(len(alpha)))
              Out[27]: [5, 4, 3, 2, 1, 0]
              
              In [28]: s = slice(None, 3, -1)
              
              In [29]: range(*s.indices(len(alpha)))
              Out[29]: [5, 4]
              

              注意:这篇文章最初写在我的博客The Intelligence Behind Python Slices

              【讨论】:

              • 最后,我在这里找到了一些关于为什么切片参数startstop和防错的解释。
              【解决方案14】:

              Python 切片符号:

              a[start:end:step]
              
              • 对于startend,负值被解释为相对于序列的结尾。
              • end 的正索引表示要包含的最后一个元素之后的位置。
              • 空白值默认如下:[+0:-0:1]
              • 使用否定步骤反转startend 的解释

              符号扩展到(numpy)矩阵和多维数组。例如,要对整个列进行切片,您可以使用:

              m[::,0:2:] ## slice the first two columns
              

              切片保存数组元素的引用,而不是副本。如果要单独复制一个数组,可以使用deepcopy()

              【讨论】:

                【解决方案15】:

                您还可以使用切片分配从列表中删除一个或多个元素:

                r = [1, 'blah', 9, 8, 2, 3, 4]
                >>> r[1:4] = []
                >>> r
                [1, 2, 3, 4]
                

                【讨论】:

                  【解决方案16】:

                  这只是一些额外的信息...... 考虑下面的列表

                  >>> l=[12,23,345,456,67,7,945,467]
                  

                  反转列表的其他一些技巧:

                  >>> l[len(l):-len(l)-1:-1]
                  [467, 945, 7, 67, 456, 345, 23, 12]
                  
                  >>> l[:-len(l)-1:-1]
                  [467, 945, 7, 67, 456, 345, 23, 12]
                  
                  >>> l[len(l)::-1]
                  [467, 945, 7, 67, 456, 345, 23, 12]
                  
                  >>> l[::-1]
                  [467, 945, 7, 67, 456, 345, 23, 12]
                  
                  >>> l[-1:-len(l)-1:-1]
                  [467, 945, 7, 67, 456, 345, 23, 12]
                  

                  【讨论】:

                    【解决方案17】:

                    作为一般规则,使用大量硬编码索引值编写代码会导致可读性 和维护混乱。例如,如果一年后你回到代码中,你会 看看它,想知道你在写它时在想什么。显示的解决方案 只是一种更清楚地说明您的代码实际在做什么的方式。 一般来说,内置的 slice() 创建一个切片对象,可以在切片的任何地方使用 被允许。例如:

                    >>> items = [0, 1, 2, 3, 4, 5, 6]
                    >>> a = slice(2, 4)
                    >>> items[2:4]
                    [2, 3]
                    >>> items[a]
                    [2, 3]
                    >>> items[a] = [10,11]
                    >>> items
                    [0, 1, 10, 11, 4, 5, 6]
                    >>> del items[a]
                    >>> items
                    [0, 1, 4, 5, 6]
                    

                    如果你有一个切片实例 s,你可以通过查看它来获取更多关于它的信息 s.start、s.stop 和 s.step 属性。例如:

                    >>> a = slice(10, 50, 2)
                    >>> a.start
                    10
                    >>> a.stop
                    50
                    >>> a.step
                    2
                    >>>
                    

                    【讨论】:

                      【解决方案18】:

                      前面的答案没有讨论使用著名的NumPy 包可以实现的多维数组切片:

                      切片也可以应用于多维数组。

                      # Here, a is a NumPy array
                      
                      >>> a
                      array([[ 1,  2,  3,  4],
                             [ 5,  6,  7,  8],
                             [ 9, 10, 11, 12]])
                      >>> a[:2, 0:3:2]
                      array([[1, 3],
                             [5, 7]])
                      

                      逗号前的“:2”作用于第一维,逗号后的“0:3:2”作用于第二维。

                      【讨论】:

                      • 只是一个友好的提醒,你不能在 Python list 上执行此操作,而只能在 Numpy 中的 array 上执行此操作
                      【解决方案19】:

                      1。切片符号

                      为简单起见,请记住slice只有一种形式:

                      s[start:end:step]
                      

                      这是它的工作原理:

                      • s: 可以切片的对象
                      • start:开始迭代的第一个索引
                      • end:最后一个索引,注意end 索引不会包含在结果切片中
                      • step:每step索引选择元素

                      另外一个导入的东西:所有start,end,step都可以省略!如果省略,将使用它们的默认值:0,len(s) ,1 相应地。

                      所以可能的变化是:

                      # Mostly used variations
                      s[start:end]
                      s[start:]
                      s[:end]
                      
                      # Step-related variations
                      s[:end:step]
                      s[start::step]
                      s[::step]
                      
                      # Make a copy
                      s[:]
                      

                      注意:如果start &gt;= end(仅考虑step&gt;0),Python 将返回一个空切片[]

                      2。陷阱

                      以上部分解释了 slice 工作原理的核心特性,它适用于大多数场合。但是,您可能需要注意一些陷阱,本部分将对其进行解释。

                      负索引

                      首先让 Python 学习者感到困惑的是索引可能是负数! 不要惊慌:负数表示倒数。

                      例如:

                      s[-5:]    # Start at the 5th index from the end of array,
                                # thus returning the last 5 elements.
                      s[:-5]    # Start at index 0, and end until the 5th index from end of array,
                                # thus returning s[0:len(s)-5].
                      

                      负步骤

                      让事情更令人困惑的是 step 也可以是负数!

                      负步意味着向后迭代数组:从结束到开始,包括结束索引,并且从结果中排除开始索引。

                      注意:当step为负数时,start的默认值为len(s)(而end不等于0,因为s[::-1]包含s[0]) .例如:

                      s[::-1]            # Reversed slice
                      s[len(s)::-1]      # The same as above, reversed slice
                      s[0:len(s):-1]     # Empty list
                      

                      超出范围错误?

                      感到惊讶:当索引超出范围时,slice 不会引发 IndexError!

                      如果索引超出范围,Python会根据情况尽量将索引设置为0len(s)。例如:

                      s[:len(s)+5]      # The same as s[:len(s)]
                      s[-len(s)-5::]    # The same as s[0:]
                      s[len(s)+5::-1]   # The same as s[len(s)::-1], and the same as s[::-1]
                      

                      3。示例

                      让我们用例子来结束这个答案,解释我们所讨论的一切:

                      # Create our array for demonstration
                      In [1]: s = [i for i in range(10)]
                      
                      In [2]: s
                      Out[2]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
                      
                      In [3]: s[2:]   # From index 2 to last index
                      Out[3]: [2, 3, 4, 5, 6, 7, 8, 9]
                      
                      In [4]: s[:8]   # From index 0 up to index 8
                      Out[4]: [0, 1, 2, 3, 4, 5, 6, 7]
                      
                      In [5]: s[4:7]  # From index 4 (included) up to index 7(excluded)
                      Out[5]: [4, 5, 6]
                      
                      In [6]: s[:-2]  # Up to second last index (negative index)
                      Out[6]: [0, 1, 2, 3, 4, 5, 6, 7]
                      
                      In [7]: s[-2:]  # From second last index (negative index)
                      Out[7]: [8, 9]
                      
                      In [8]: s[::-1] # From last to first in reverse order (negative step)
                      Out[8]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
                      
                      In [9]: s[::-2] # All odd numbers in reversed order
                      Out[9]: [9, 7, 5, 3, 1]
                      
                      In [11]: s[-2::-2] # All even numbers in reversed order
                      Out[11]: [8, 6, 4, 2, 0]
                      
                      In [12]: s[3:15]   # End is out of range, and Python will set it to len(s).
                      Out[12]: [3, 4, 5, 6, 7, 8, 9]
                      
                      In [14]: s[5:1]    # Start > end; return empty list
                      Out[14]: []
                      
                      In [15]: s[11]     # Access index 11 (greater than len(s)) will raise an IndexError
                      ---------------------------------------------------------------------------
                      IndexError                                Traceback (most recent call last)
                      <ipython-input-15-79ffc22473a3> in <module>()
                      ----> 1 s[11]
                      
                      IndexError: list index out of range
                      

                      【讨论】:

                        【解决方案20】:

                        在我看来,如果您按照以下方式查看 Python 字符串切片表示法(请继续阅读),您会更好地理解和记住它。

                        让我们使用以下字符串...

                        azString = "abcdefghijklmnopqrstuvwxyz"
                        

                        对于那些不知道的人,您可以使用 azString[x:y] 表示法从 azString 创建任何子字符串

                        来自其他编程语言,这就是常识受到损害的时候。 x 和 y 是什么?

                        我不得不坐下来运行几个场景,以寻求一种记忆技术,这将帮助我记住 x 和 y 是什么,并帮助我在第一次尝试时正确地分割字符串。

                        我的结论是 x 和 y 应该被视为围绕我们想要额外的字符串的边界索引。所以我们应该看到表达式为azString[index1, index2],或者更清晰的为azString[index_of_first_character, index_after_the_last_character]

                        这是一个可视化的示例......

                        Letters   a b c d e f g h i j ...
                                 ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
                                     ┊           ┊
                        Indexes  0 1 2 3 4 5 6 7 8 9 ...
                                     ┊           ┊
                        cdefgh    index1       index2
                        

                        所以您所要做的就是将 index1 和 index2 设置为围绕所需子字符串的值。例如,要获取子字符串“cdefgh”,可以使用azString[2:8],因为“c”左侧的索引是2,而“h”右侧的索引是8。

                        请记住,我们正在设定界限。这些边界是您可以放置​​一些括号的位置,这些括号将像这样包裹在子字符串周围...

                        a b [ c d e f g h ] i j

                        这个技巧一直有效,而且很容易记住。

                        【讨论】:

                          【解决方案21】:

                          我个人认为它就像一个for 循环:

                          a[start:end:step]
                          # for(i = start; i < end; i += step)
                          

                          另外,请注意,startend 的负值是相对于列表末尾的,并在上面的示例中由 given_index + a.shape[0] 计算得出。

                          【讨论】:

                            【解决方案22】:

                            切片规则如下:

                            [lower bound : upper bound : step size]
                            

                            I-upper boundlower bound转换成常用符号。

                            II-然后检查step size还是值。

                            (i)如果step size是一个正值upper bound应该大于lower bound,否则@打印 987654328@。 例如

                            s="Welcome"
                            s1=s[0:3:1]
                            print(s1)
                            

                            输出:

                            Wel
                            

                            但是,如果我们运行以下代码:

                            s="Welcome"
                            s1=s[3:0:1]
                            print(s1)
                            

                            它将返回一个空字符串

                            (ii) 如果step size负值,则upper bound小于 lower bound,否则@将打印 987654335@。例如:

                            s="Welcome"
                            s1=s[3:0:-1]
                            print(s1)
                            

                            输出:

                            cle
                            

                            但是如果我们运行以下代码:

                            s="Welcome"
                            s1=s[0:5:-1]
                            print(s1)
                            

                            输出将是一个空字符串

                            因此在代码中:

                            str = 'abcd'
                            l = len(str)
                            str2 = str[l-1:0:-1]    #str[3:0:-1] 
                            print(str2)
                            str2 = str[l-1:-1:-1]    #str[3:-1:-1]
                            print(str2)
                            

                            在第一个str2=str[l-1:0:-1] 中,upper bound小于lower bound,因此打印了dcb

                            然而在str2=str[l-1:-1:-1]中,upper bound不小于lower bound(将lower bound转换为负值-1:因为最后一个元素的 index 是 -1 和 3)。

                            【讨论】:

                              【解决方案23】:
                              #!/usr/bin/env python
                              
                              def slicegraphical(s, lista):
                              
                                  if len(s) > 9:
                                      print """Enter a string of maximum 9 characters,
                                  so the printig would looki nice"""
                                      return 0;
                                  # print " ",
                                  print '  '+'+---' * len(s) +'+'
                                  print ' ',
                                  for letter in s:
                                      print '| {}'.format(letter),
                                  print '|'
                                  print " ",; print '+---' * len(s) +'+'
                              
                                  print " ",
                                  for letter in range(len(s) +1):
                                      print '{}  '.format(letter),
                                  print ""
                                  for letter in range(-1*(len(s)), 0):
                                      print ' {}'.format(letter),
                                  print ''
                                  print ''
                              
                              
                                  for triada in lista:
                                      if len(triada) == 3:
                                          if triada[0]==None and triada[1] == None and triada[2] == None:
                                              # 000
                                              print s+'[   :   :   ]' +' = ', s[triada[0]:triada[1]:triada[2]]
                                          elif triada[0] == None and triada[1] == None and triada[2] != None:
                                              # 001
                                              print s+'[   :   :{0:2d} ]'.format(triada[2], '','') +' = ', s[triada[0]:triada[1]:triada[2]]
                                          elif triada[0] == None and triada[1] != None and triada[2] == None:
                                              # 010
                                              print s+'[   :{0:2d} :   ]'.format(triada[1]) +' = ', s[triada[0]:triada[1]:triada[2]]
                                          elif triada[0] == None and triada[1] != None and triada[2] != None:
                                              # 011
                                              print s+'[   :{0:2d} :{1:2d} ]'.format(triada[1], triada[2]) +' = ', s[triada[0]:triada[1]:triada[2]]
                                          elif triada[0] != None and triada[1] == None and triada[2] == None:
                                              # 100
                                              print s+'[{0:2d} :   :   ]'.format(triada[0]) +' = ', s[triada[0]:triada[1]:triada[2]]
                                          elif triada[0] != None and triada[1] == None and triada[2] != None:
                                              # 101
                                              print s+'[{0:2d} :   :{1:2d} ]'.format(triada[0], triada[2]) +' = ', s[triada[0]:triada[1]:triada[2]]
                                          elif triada[0] != None and triada[1] != None and triada[2] == None:
                                              # 110
                                              print s+'[{0:2d} :{1:2d} :   ]'.format(triada[0], triada[1]) +' = ', s[triada[0]:triada[1]:triada[2]]
                                          elif triada[0] != None and triada[1] != None and triada[2] != None:
                                              # 111
                                              print s+'[{0:2d} :{1:2d} :{2:2d} ]'.format(triada[0], triada[1], triada[2]) +' = ', s[triada[0]:triada[1]:triada[2]]
                              
                                      elif len(triada) == 2:
                                          if triada[0] == None and triada[1] == None:
                                              # 00
                                              print s+'[   :   ]    ' + ' = ', s[triada[0]:triada[1]]
                                          elif triada[0] == None and triada[1] != None:
                                              # 01
                                              print s+'[   :{0:2d} ]    '.format(triada[1]) + ' = ', s[triada[0]:triada[1]]
                                          elif triada[0] != None and triada[1] == None:
                                              # 10
                                              print s+'[{0:2d} :   ]    '.format(triada[0]) + ' = ', s[triada[0]:triada[1]]
                                          elif triada[0] != None and triada[1] != None:
                                              # 11
                                              print s+'[{0:2d} :{1:2d} ]    '.format(triada[0],triada[1]) + ' = ', s[triada[0]:triada[1]]
                              
                                      elif len(triada) == 1:
                                          print s+'[{0:2d} ]        '.format(triada[0]) + ' = ', s[triada[0]]
                              
                              
                              if __name__ == '__main__':
                                  # Change "s" to what ever string you like, make it 9 characters for
                                  # better representation.
                                  s = 'COMPUTERS'
                              
                                  # add to this list different lists to experement with indexes
                                  # to represent ex. s[::], use s[None, None,None], otherwise you get an error
                                  # for s[2:] use s[2:None]
                              
                                  lista = [[4,7],[2,5,2],[-5,1,-1],[4],[-4,-6,-1], [2,-3,1],[2,-3,-1], [None,None,-1],[-5,None],[-5,0,-1],[-5,None,-1],[-1,1,-2]]
                              
                                  slicegraphical(s, lista)
                              

                              您可以运行此脚本并对其进行试验,以下是我从脚本中获得的一些示例。

                                +---+---+---+---+---+---+---+---+---+
                                | C | O | M | P | U | T | E | R | S |
                                +---+---+---+---+---+---+---+---+---+
                                0   1   2   3   4   5   6   7   8   9   
                               -9  -8  -7  -6  -5  -4  -3  -2  -1 
                              
                              COMPUTERS[ 4 : 7 ]     =  UTE
                              COMPUTERS[ 2 : 5 : 2 ] =  MU
                              COMPUTERS[-5 : 1 :-1 ] =  UPM
                              COMPUTERS[ 4 ]         =  U
                              COMPUTERS[-4 :-6 :-1 ] =  TU
                              COMPUTERS[ 2 :-3 : 1 ] =  MPUT
                              COMPUTERS[ 2 :-3 :-1 ] =  
                              COMPUTERS[   :   :-1 ] =  SRETUPMOC
                              COMPUTERS[-5 :   ]     =  UTERS
                              COMPUTERS[-5 : 0 :-1 ] =  UPMO
                              COMPUTERS[-5 :   :-1 ] =  UPMOC
                              COMPUTERS[-1 : 1 :-2 ] =  SEUM
                              [Finished in 0.9s]
                              

                              使用否定步长时,请注意答案右移 1。

                              【讨论】:

                                【解决方案24】:

                                我的大脑似乎很乐意接受lst[start:end] 包含start-th 项。我什至可以说这是一个“自然假设”。

                                但偶尔会出现疑问,我的大脑要求确保它不包含end-th 元素。

                                在这些时刻,我依靠这个简单的定理:

                                for any n,    lst = lst[:n] + lst[n:]
                                

                                这个漂亮的属性告诉我lst[start:end] 不包含end-th 项,因为它在lst[end:] 中。

                                请注意,这个定理对于任何n 都是正确的。例如,您可以检查

                                lst = range(10)
                                lst[:-42] + lst[-42:] == lst
                                

                                返回True

                                【讨论】:

                                  【解决方案25】:

                                  在 Python 中,最基本的切片形式如下:

                                  l[start:end]
                                  

                                  其中l 是某个集合,start 是包含索引,end 是排除索引。

                                  In [1]: l = list(range(10))
                                  
                                  In [2]: l[:5] # First five elements
                                  Out[2]: [0, 1, 2, 3, 4]
                                  
                                  In [3]: l[-5:] # Last five elements
                                  Out[3]: [5, 6, 7, 8, 9]
                                  

                                  从头开始切片时,可以省略零索引,切片到末尾时,可以省略最终索引,因为它是多余的,所以不要冗长:

                                  In [5]: l[:3] == l[0:3]
                                  Out[5]: True
                                  
                                  In [6]: l[7:] == l[7:len(l)]
                                  Out[6]: True
                                  

                                  负整数在相对于集合末尾进行偏移时很有用:

                                  In [7]: l[:-1] # Include all elements but the last one
                                  Out[7]: [0, 1, 2, 3, 4, 5, 6, 7, 8]
                                  
                                  In [8]: l[-3:] # Take the last three elements
                                  Out[8]: [7, 8, 9]
                                  

                                  切片时可以提供超出范围的索引,例如:

                                  In [9]: l[:20] # 20 is out of index bounds, and l[20] will raise an IndexError exception
                                  Out[9]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
                                  
                                  In [11]: l[-20:] # -20 is out of index bounds, and l[-20] will raise an IndexError exception
                                  Out[11]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
                                  

                                  请记住,对集合进行切片的结果是一个全新的集合。此外,当在赋值中使用切片表示法时,切片赋值的长度不需要相同。分配切片之前和之后的值将被保留,并且集合将缩小或增长以包含新值:

                                  In [16]: l[2:6] = list('abc') # Assigning fewer elements than the ones contained in the sliced collection l[2:6]
                                  
                                  In [17]: l
                                  Out[17]: [0, 1, 'a', 'b', 'c', 6, 7, 8, 9]
                                  
                                  In [18]: l[2:5] = list('hello') # Assigning more elements than the ones contained in the sliced collection l [2:5]
                                  
                                  In [19]: l
                                  Out[19]: [0, 1, 'h', 'e', 'l', 'l', 'o', 6, 7, 8, 9]
                                  

                                  如果省略开始和结束索引,则会复制集合:

                                  In [14]: l_copy = l[:]
                                  
                                  In [15]: l == l_copy and l is not l_copy
                                  Out[15]: True
                                  

                                  如果在执行赋值操作时省略了开始和结束索引,则集合的整个内容将被引用的内容的副本替换:

                                  In [20]: l[:] = list('hello...')
                                  
                                  In [21]: l
                                  Out[21]: ['h', 'e', 'l', 'l', 'o', '.', '.', '.']
                                  

                                  除了基本切片之外,还可以应用以下表示法:

                                  l[start:end:step]
                                  

                                  其中l 是一个集合,start 是一个包含索引,end 是一个排除索引,step 是一个步幅,可用于获取每个nth 项在l.

                                  In [22]: l = list(range(10))
                                  
                                  In [23]: l[::2] # Take the elements which indexes are even
                                  Out[23]: [0, 2, 4, 6, 8]
                                  
                                  In [24]: l[1::2] # Take the elements which indexes are odd
                                  Out[24]: [1, 3, 5, 7, 9]
                                  

                                  在 Python 中使用 step 提供了一个有用的技巧来反转集合:

                                  In [25]: l[::-1]
                                  Out[25]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
                                  

                                  step 也可以使用负整数,如下例所示:

                                  In[28]:  l[::-2]
                                  Out[28]: [9, 7, 5, 3, 1]
                                  

                                  但是,对step 使用负值可能会变得非常混乱。此外,为了成为Pythonic,您应该避免在单个切片中使用startendstep。如果需要,请考虑在两个作业中执行此操作(一个用于切片,另一个用于跨步)。

                                  In [29]: l = l[::2] # This step is for striding
                                  
                                  In [30]: l
                                  Out[30]: [0, 2, 4, 6, 8]
                                  
                                  In [31]: l = l[1:-1] # This step is for slicing
                                  
                                  In [32]: l
                                  Out[32]: [2, 4, 6]
                                  

                                  【讨论】:

                                    【解决方案26】:

                                    我想添加一个 Hello, World! 示例,为初学者解释切片的基础知识。这对我帮助很大。

                                    让我们有一个包含六个值的列表['P', 'Y', 'T', 'H', 'O', 'N']

                                    +---+---+---+---+---+---+
                                    | P | Y | T | H | O | N |
                                    +---+---+---+---+---+---+
                                      0   1   2   3   4   5
                                    

                                    现在该列表中最简单的部分是它的子列表。符号是[&lt;index&gt;:&lt;index&gt;],关键是这样读:

                                    [ start cutting before this index : end cutting before this index ]
                                    

                                    现在,如果您从上面的列表中切出[2:5],就会发生这种情况:

                                            |           |
                                    +---+---|---+---+---|---+
                                    | P | Y | T | H | O | N |
                                    +---+---|---+---+---|---+
                                      0   1 | 2   3   4 | 5
                                    

                                    索引2的元素和另一个索引5的元素之前进行了剪切。所以结果将是这两个剪辑之间的一个切片,一个列表['T', 'H', 'O']

                                    【讨论】:

                                      【解决方案27】:

                                      前面的大部分答案都解决了有关切片符号的问题。

                                      用于切片的扩展索引语法为aList[start:stop:step],基本示例如下:

                                      :

                                      更多切片示例:15 Extended Slices

                                      【讨论】:

                                        【解决方案28】:

                                        下面是一个字符串索引的例子:

                                         +---+---+---+---+---+
                                         | H | e | l | p | A |
                                         +---+---+---+---+---+
                                         0   1   2   3   4   5
                                        -5  -4  -3  -2  -1
                                        
                                        str="Name string"
                                        

                                        切片示例:[start:end:step]

                                        str[start:end] # Items start through end-1
                                        str[start:]    # Items start through the rest of the array
                                        str[:end]      # Items from the beginning through end-1
                                        str[:]         # A copy of the whole array
                                        

                                        以下是示例用法:

                                        print str[0] = N
                                        print str[0:2] = Na
                                        print str[0:7] = Name st
                                        print str[0:7:2] = Nm t
                                        print str[0:-1:2] = Nm ti
                                        

                                        【讨论】:

                                          【解决方案29】:

                                          如果您觉得切片中的负索引令人困惑,这里有一个非常简单的思考方法:只需将负索引替换为len - index。例如,将 -3 替换为 len(list) - 3

                                          说明切片内部作用的最佳方式是在实现此操作的代码中显示它:

                                          def slice(list, start = None, end = None, step = 1):
                                            # Take care of missing start/end parameters
                                            start = 0 if start is None else start
                                            end = len(list) if end is None else end
                                          
                                            # Take care of negative start/end parameters
                                            start = len(list) + start if start < 0 else start
                                            end = len(list) + end if end < 0 else end
                                          
                                            # Now just execute a for-loop with start, end and step
                                            return [list[i] for i in range(start, end, step)]
                                          

                                          【讨论】:

                                            【解决方案30】:

                                            我不认为Python tutorial 图表(在其他各种答案中引用)是好的,因为这个建议适用于积极的步伐,但不适用于消极的步伐。

                                            这是图表:

                                             +---+---+---+---+---+---+
                                             | P | y | t | h | o | n |
                                             +---+---+---+---+---+---+
                                             0   1   2   3   4   5   6
                                            -6  -5  -4  -3  -2  -1
                                            
                                            

                                            从图中,我预计 a[-4,-6,-1]yP 但它是 ty

                                            >>> a = "Python"
                                            >>> a[2:4:1] # as expected
                                            'th'
                                            >>> a[-4:-6:-1] # off by 1
                                            'ty'
                                            

                                            始终有效的方法是考虑字符或插槽并将索引用作半开区间——如果是正步幅则右开,如果步幅负则左开。

                                            这样,我可以将a[-4:-6:-1] 视为区间术语中的a(-6,-4]

                                             +---+---+---+---+---+---+
                                             | P | y | t | h | o | n |
                                             +---+---+---+---+---+---+
                                               0   1   2   3   4   5  
                                              -6  -5  -4  -3  -2  -1
                                            
                                             +---+---+---+---+---+---+---+---+---+---+---+---+
                                             | P | y | t | h | o | n | P | y | t | h | o | n |
                                             +---+---+---+---+---+---+---+---+---+---+---+---+
                                              -6  -5  -4  -3  -2  -1   0   1   2   3   4   5  
                                            

                                            【讨论】:

                                            • 今天 2021/07/19 本人使用,qué capo aguadopd del pasado
                                            • 作为一个新手,这是一种有趣的思考方式。然而,最后一个例子,从 -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 计数有点误导,因为字符串不是这样加倍的。此外,可以参考如下的正位和负位:a[-4:-6:-1] 与 a[-4:0:-1] 相同,因为第 0 位与 -第 6 位。所以我会删除/忽略那个例子。