通过字符串某个字符的索引,可以得到相应字符,此外,还可以通过指定索引范围,得到多个字符,此操作称为切片( Slicing )。
Python 语言中关于字符串切片的一般操作形式如图4-2-5所示——这种形式适用于所有的序列类对象。

图4-2-5 切片的形式
图4-2-5中的各个符号含义如下:
S :字符串或者引用字符串的变量;start :切片开始位置索引。如果是从第一个字符开始,可以省略;end :切片结束位置索引(切片中不含此索引对应的字符)。如果是到最后一个字符结束(含最后一个),可以省略;step :切片的步长,如果省略则为默认值 step=1。可为正整数,也可以为负整数。下面就按照此操作形式,了解字符串的切片。
首先,考虑 step=1 的情形,即省略步长值。
>>> book
'python book'
>>> book[1: 8] # (21)
'ython b'
>>> book[1: 8: 1] # (22)
'ython b'
注释(21)没有声明 step 的值,其效果与(22)中声明 step=1 一样。
以注释(21)的切片为例,得到了字符串 'python book' 的部分字符组成的字符串——就如同从原来字符串上“切”下来“片段”一样,故曰“切片”。如图4-2-6所示,从索引是 1 (含)的位置开始,依次将索引是 1、2、3、4、5、6、7 的字符“切”出来,到索引是 8 (不含)的位置之前结束。

图4-2-6 字符串切片示意
从结果中可以看出,结束索引 8 所对应的字符没有在“被切”之列,这是 Python 中的普遍规则,为了便于记忆,可以概括为“前包括,后不包括”。
再观察图4-2-6,根据4.2.4节所学可知,字符串中每个字符对应着两个索引,例如字符 'y' 的索引是 1 和 -10 。按照图4-2-5所示的操作形式,start 对应的是切片开始位置的索引,并未要求是“从左向右”还是“从右向左”创建的索引,因此,可以尝试 book[-10: 8] 等操作是否可行,结果如何?勇敢地尝试:
>>> book[-10: 8]
'ython b'
>>> book[1: -3]
'ython b'
>>> book[-10: -3]
'ython b'
以上三项以及注释(21),实现的最终效果都一样,请读者通过这些操作理解图4-2-5中 start 和 end 的含义。
当原字符串被“切”出了一部分,是否因此而“破坏”原字符串了?
>>> book
'python book'
这说明所谓的“切片”,就是比照着索引在原字符串中所对应的字符,重新创建了一个字符串对象。从最终结果看,貌似是从原字符串上“切下来的一部分”。
如果切片开始的索引是 0 ,可以不写该索引:
>>> book[: 8]
'python b'
>>> book[0: 8]
'python b'
如果切片结束的索引是字符串的最后一个,例如图4-2-6所示的字符串,最后一个字符的索引是 10 或 -1 ,也可以省略:
>>> book[7:] # (23)
'book'
>>> book[7: 11] # (24)
'book'
>>> book[7: 10] # (25)
'boo'
仔细对比上述三种操作及其结果,并理解:
book[11] 是不允许的,详见4.2.4节。10 ,根据前述“前包括,后不包括”的原则,索引 10 所对应的字符不再“切片”之内。如果 book[ : ] 又会如何?
>>> book[:]
'python book'
读者是否能解释上述结果?
省略了切片开始的索引,则意味着从第一个字符开始“切”;省略了切片结束的索引,则意味着“切”到最后一个字符。故得到了“整个”字符串。
再进一步,现在得到的“整个”字符串与原来的字符串相比,是否是同一个对象——请参见第3章3.6.2节中对“相等”和“同一”的讨论。
>>> book2 = book[:]
>>> book2 == book
True
>>> book2 is book
True
变量 book2 和 book 引用了同一个对象,所以,book2 = book[:] 并不是将原字符串复制了一份,没有生成新的字符串,这点请读者注意。
以上各项操作,均没有声明 step 的值,即默认步长是 1 ,下面尝试修改步长的值。
>>> book[::2]
'pto ok'
>>> book[1: 10: 3]
'yob'
对照图4-2-6,不难理解上述操作,此处不再赘述。不过,在前面解释 step 时,曾指出它的值还可以是负整数——“迈出 -1 步,难道是向后走吗?”,说对了。

图4-2-7 步长是正整数
如果把字符串看做“一维”的,如图4-2-7那样以箭头所指方向为正方向——这种规定非常符合习惯,沿着正方向“切”的步长就是“正整数”——图示中步长是 2 。图4-2-7所示的切片操作即可理解为:沿着正方向“从左向右”,“先看到”字符 'y',其索引是 1 或 -10——作为 start 的值,“后看到”字符 'o' ,其索引是 8 或 -3——作为 end 的值。
>>> book[1: 8: 2]
'yhnb'
>>> book[1: -3: 2]
'yhnb'
>>> book[-10: 8: 2]
'yhnb'
>>> book[-10: -3: 2]
'yhnb'
有向量知识的读者肯定知道(关于向量的知识请参阅拙作《机器学习数学基础》),在一维空间中,正数常常表示与规定正方向同向的向量,负数常常表示与规定正方向反向的向量。在图4-2-7中,已经规定了正方向,如果步长是正整数,则意味着“切”的方向与正方向同向;如果步长是负整数,显然意味着“切”的方向与正方向反向,即“从右开始,向左切”,此时“先看到”的是字符 'o' ,其索引是 8 或 -3——作为 start 的值;“后看到”的是字符 'y',其索引是 1 或 -10——作为 end 的值,如图4-2-8所示,并按照从先到后的顺序将字符从字符串中“切”出来。

图4-2-8 步长是负整数
>>> book[8: 1: -2]
'o ot'
>>> book[-3: 1: -2]
'o ot'
>>> book[8: -10: -2]
'o ot'
>>> book[-3: -10: -2]
'o ot'
至此,请读者稍作停留,对照图4-2-7和图4-2-8以及相关操作,再次理解图4-2-5中的 start、end、step 的含义,并做适当总结。
为了进一步检验自己对切片操作的理解,可以在交互模式中执行如下表达式:
>>> book[: : -1]
'koob nohtyp'
>>> book
'python book'
将切片 book[: : -1] 返回的结果与原字符串对比,会发现此结果是对原字符串的反序——一般来讲,反序之后的字符串会与原字符串不同,除非是“回文”,比如字符串 noon ,正序和反序都一样。这是一种文字游戏,不仅仅见于英文,在中文中也有不少,比如“口罩罩口”等(在第7章7.5节专门编写函数来判断字符串是否为“回文”)。
★自古以来,就有“回文诗”,即“正读”、“倒读”都能成诗,毫无违和感,比如苏轼的诗《记梦》:“空花落尽酒倾漾,日上山融雪涨江。红焙浅瓯新火活,龙团小辗斗晴窗。”就是一首回文诗。 ”
>>> first = '空花落尽酒倾漾'
>>> second = '日上山融雪涨江'
>>> third = '红焙浅瓯新火活'
>>> forth = '龙团小辗斗晴窗'
>>> poem = first + "," + second + "。\n" + third + "," + forth + "。"
>>> print(poem)
空花落尽酒倾漾,日上山融雪涨江。
红焙浅瓯新火活,龙团小辗斗晴窗。
>>> poem2 = forth[::-1] + "," + third[::-1] + "。\n" + second[::-1] + "," + first[::-1] + "。"
>>> print(poem2)
窗晴斗辗小团龙,活火新瓯浅焙红。
江涨雪融山上日,漾倾酒尽落花空。