Python的切片表示法是如何工作的?也就是说:当我编写[x:y:z]、a[:]、a]::2]等代码时,我如何理解哪些元素最终会出现在切片中?请在适当的地方附上参考资料。


另请参见:为什么切片和范围上限是互斥的?


当前回答

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

首先了解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

从起点开始,一步一步递增,不要到达终点。非常简单。

关于消极步骤,需要记住的一点是,停止总是被排除的终点,无论它是高还是低。如果您希望相同的切片以相反的顺序进行,则单独进行反转会更为简单:例如,“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]

不要担心“无”的细节——只需记住,省略开始和/或停止总是正确的做法,以提供整个序列。

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

其他回答

以下是字符串索引的示例:

 +---+---+---+---+---+
 | H | e | l | p | A |
 +---+---+---+---+---+
 0   1   2   3   4   5
-5  -4  -3  -2  -1

str="Name string"

切片示例:[开始:结束:步骤]

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

1.切片符号

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

s[start:end:step]

下面是它的工作原理:

s: 可以切片的物体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>=end(仅在步骤>0时考虑),Python将返回一个空切片[]。

2.陷阱

上面的部分解释了切片如何工作的核心特性,它将在大多数情况下工作。然而,可能会有陷阱,您应该注意,本部分将对它们进行解释。

负面指数

让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为负值时,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

超出范围错误?

请注意:当索引超出范围时,切片不会引发IndexError!

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

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

我自己使用“元素之间的索引点”方法来思考它,但描述它的一种方式有时有助于其他人获得它:

mylist[X:Y]

X是所需的第一个元素的索引。Y是不需要的第一个元素的索引。

您可以使用切片语法返回字符序列。

指定用冒号分隔的开始和结束索引,以返回字符串的一部分。

例子:

获取从位置2到位置5的字符(不包括):

b = "Hello, World!"
print(b[2:5])

从开始切片

通过省略起始索引,范围将从第一个字符开始:

例子:

获取从开始到位置5的字符(不包括):

b = "Hello, World!"
print(b[:5])

切片到底

通过省略结束索引,范围将结束:

例子:

从位置2获取字符,一直到结尾:

b = "Hello, World!"
print(b[2:])

负索引

使用负索引从字符串末尾开始切片:实例

获取字符:

来自:“世界!”中的“o”(位置-5)

至,但不包括:“世界!”中的“d”(位置-2):

b = "Hello, World!"
print(b[-5:-2])

这里有一个简单的记忆方法,可以记住它是如何工作的:

S L*I*C*E*切片的“i”位于第一位,代表包容,“e”排在最后,代表独占。

所以array[j:k]将包括第j个元素,并排除第k个元素。