本节书摘来自华章社区《编写高质量python代码的59个有效方法》一书中的第5条:了解切割序列的办法,作者[美]布雷特·斯拉特金(brett slatkin),更多章节内容可以访问云栖社区“华章社区”公众号查看
第5条:了解切割序列的办法
python提供了一种把序列切成小块的写法。这种切片(slice)操作,使得开发者能够轻易地访问由序列中的某些元素所构成的子集。最简单的用法,就是对内置的list、str和bytes进行切割。切割操作还可以延伸到实现了__getitem__和__setitem__这两个特殊方法的python类上(参见本书第28条)。
切割操作的基本写法是somelist[start:end],其中start(起始索引)所指的元素涵盖在切割后的范围内,而end(结束索引)所指的元素则不包括在切割结果之中。
如果从列表开头获取切片,那就不要在start那里写上0,而是应该把它留空,这样代码看起来会清爽一些。
如果切片一直要取到列表末尾,那就应该把end留空,因为即便写了,也是多余。
在指定切片起止索引时,若要从列表尾部向前算,则可使用负值来表示相关偏移量。如果采用下面这些写法来切割列表,那么即便是刚刚接触代码的人也能立刻明白程序的意图。由于这些写法都不会令人惊讶,所以笔者推荐大家在代码中放心地使用。
切割列表时,即便start或end索引越界也不会出问题。利用这一特性,我们可以限定输入序列的最大长度。
反之,访问列表中的单个元素时,下标不能越界,否则会导致异常。
请注意,如果使用负变量作为start索引来切割列表,那么在极个别情况下,可能会导致奇怪的结果。例如,somelist[-n:]这个表达式,在n大于1时可以正常运作,如当n为3时,somelist[-3:]的结果是正常的。然而,当n为0时,表达式somelist[-0:]则成了原列表的一份拷贝。
对原列表进行切割之后,会产生另外一份全新的列表。系统依然维护着指向原列表中各个对象的引用。在切割后得到的新列表上进行修改,不会影响原列表。
在赋值时对左侧列表使用切割操作,会把该列表中处在指定范围内的对象替换为新值。与元组(tuple)的赋值(如a, b = c[:2])不同,此切片的长度无需新值的个数相等。位于切片范围之前及之后的那些值都保留不变。列表会根据新值的个数相应地扩张或收缩。
如果对赋值操作右侧的列表使用切片,而把切片的起止索引都留空,那就会产生一份原列表的拷贝。
如果对赋值操作左侧的列表使用切片,而又没有指定起止索引,那么系统会把右侧的新值复制一份,并用这份拷贝来替换左侧列表的全部内容,而不会重新分配新的列表。
要点
不要写多余的代码:当start索引为0,或end索引为序列长度时,应该将其省略。
切片操作不会计较start与end索引是否越界,这使得我们很容易就能从序列的前端或后端开始,对其进行范围固定的切片操作(如a[:20]或a[-20:])。
对list赋值的时候,如果使用切片操作,就会把原列表中处在相关范围内的值替换成新值,即便它们的长度不同也依然可以替换。