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


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


当前回答

Python教程对此进行了讨论(向下滚动一点,直到您了解到关于切片的部分)。

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

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

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

其他回答

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

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

azString = "abcdefghijklmnopqrstuvwxyz"

对于不知道的人,可以使用符号azString[x:y]从azString创建任何子字符串

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

为了寻找一种记忆技巧,我不得不坐下来运行了几个场景,帮助我记住x和y是什么,并帮助我在第一次尝试时正确地切分字符串。

我的结论是,x和y应该被视为围绕我们想要增加的字符串的边界索引。因此,我们应该将表达式视为azString[index1,index2],或者更清晰地视为azString[index_of_first_charactere,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公司

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

如果我们可以将切片与范围联系起来,这很容易理解,因为范围给出了索引。我们可以将切片分为以下两类:


1.无台阶或台阶>0。例如,[i:j]或[i:j:k](k>0)

假设序列为s=[1,2,3,4,5]。

如果0<i<len(s)和0<j<len,则[i:j:k]->范围(i,j,k)

例如,[0:3:2]->范围(0,3,2)->0,2

如果i>len或j>len,则i=len或j=len

例如,[0:100:2]->范围(0,len(s),2)->范围(0,5,2)->0,2,4

如果i<0或j<0,则i=max(0,len(s)+i)或j=max

例如,[0:-3:2]->范围(0,len(s)-3,2)->范围(0,2,2)->0

例如,[0:-1:2]->范围(0,len(s)-1,2)->范围(0,4,2)->0,2

如果未指定i,则i=0

例如,[:4:2]->范围(0,4,2)->范围(4,2)->0,2

如果未指定j,则j=len(s)

例如,[0::2]->范围(0,len(s),2)->范围(0,5,2)->0,2,4


2.步骤<0。例如,[i:j:k](k<0)

假设序列为s=[1,2,3,4,5]。

如果0<i<len(s)和0<j<len,则[i:j:k]->范围(i,j,k)

例如,[5:0:-2]->范围(5,0,-2)->5,3,1

如果i>len或j>len,则i=len(s)-1或j=len(s)-1

例如,[100:0:-2]->范围(len(s)-1,0,-2)->范围(4,0,-2)->4,2

如果i<0或j<0,则i=max(-1,len(s)+i)或j=max(-1len(s)+j)

例如,[-2:-10:-2]->range(len(s)-2,-1,-2)->range(3,-1,-1)->3,1

如果未指定i,则i=len(s)-1

例如,[:0:-2]->范围(len(s)-1,0,-2)->范围(4,0,-2)->4,2

如果未指定j,则j=-1

例如,[2::-2]->范围(2,-1,-2)->2,0

例如,[::-1]->range(len(s)-1,-1,-1)->range(4,-1,1)->4,3,2,1,0


总而言之

关于序列的索引,需要记住的重要思想是

非负指数从序列中的第一项开始;负索引从序列的最后一项开始(因此仅适用于有限序列)。

换言之,负索引右移序列长度:

              0   1   2   3   4   5   6   7   ...
            -------------------------
            | a | b | c | d | e | f |
            -------------------------
...  -8  -7  -6  -5  -4  -3  -2  -1

考虑到这一点,订阅和切片很简单。

订阅

订阅使用以下语法:*

sequence[index]

订阅在索引处选择序列中的单个项目:

>>> 'abcdef'[0]
'a'
>>> 'abcdef'[-6]
'a'

订阅引发超出范围的索引的IndexError:

>>> 'abcdef'[100]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: string index out of range

切片

切片使用以下语法:**

sequence[start:stop:step]

切片选择序列中的一系列项目,从包含开始到不包含结束:

>>> 'abcdef'[0:2:1]
'ab'
>>> 'abcdef'[0:-4:1]
'ab'
>>> 'abcdef'[-6:-4:1]
'ab'
>>> 'abcdef'[-6:2:1]
'ab'
>>> 'abcdef'[1:-7:-1]
'ba'
>>> 'abcdef'[-5:-7:-1]
'ba'

切片默认为序列中最完整的项目范围,因此它对省略或等于“无”的任何开始、停止或步骤使用以下默认值:***

步骤默认为1;如果步骤为正start默认为0(第一项索引),stop默认为start+len(序列)(最后一项索引加一);如果步骤为负start默认为-1(最后一项索引),stop默认为start-len(序列)(第一项索引减一)。

>>> 'abcdef'[0:6:1]
'abcdef'
>>> 'abcdef'[::]
'abcdef'
>>> 'abcdef'[-1:-7:-1]
'fedcba'
>>> 'abcdef'[::-1]
'fedcba'

切片为等于零的步骤引发ValueError:

>>> 'abcdef'[::0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: slice step cannot be zero

切片不会为超出范围的开始或停止引发IndexError(与订阅相反):

>>> 'abcdef'[-100:100]
'abcdef'

*表达式sequence[index]和sequence__getitem_(索引)是等效的。

**表达式sequence[start:stop:step]、sequence[Sslice(start,stop,step)]和sequence__getitem_(slice(start,stop,step))是等效的,其中内置类slice实例包start,stop和step。

***表达式sequence[:]、sequence[::]和sequence[None:None:None]使用start、stop和step的默认值。

#!/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。

当我第一次看到切片语法时,有一些事情不是很明显:

>>> 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]