《编写高质量Python代码的59个有效方法》——第6条:在单次切片操作内,不要同时指定start、end和stride

本节书摘来自华章社区《编写高质量Python代码的59个有效方法》一书中的第6条:在单次切片操作内,不要同时指定start、end和stride,作者[美]布雷特·斯拉特金(Brett Slatkin),更多章节内容可以访问云栖社区“华章社区”公众号查看

第6条:在单次切片操作内,不要同时指定start、end和stride
除了基本的切片操作(参见本书第5条)之外,Python还提供了somelist[start:end:stride]形式的写法,以实现步进式切割,也就是从每n个元素里面取1个出来。例如,可以指定步进值(stride),把列表中位于偶数索引处和奇数索引处的元素分成两组:

问题在于,采用stride方式进行切片时,经常会出现不符合预期的结果。例如,Python中有一种常见的技巧,能够把以字节形式存储的字符串反转过来,这个技巧就是采用-1做步进值。

这种技巧对字节串和ASCII字符有用,但是对已经编码成UTF-8字节串的Unicode字符来说,则无法奏效。

除了-1之外,其他的负步进值有没有意义呢?请看下面的例子。

上例中,::2表示从头部开始,每两个元素选取一个。::-2则表示从尾部开始,向前选取,每两个元素里选一个。
2::2是什么意思?-2::-2、-2:2:-2和2:2:-2又是什么意思?请看下面的例子。

通过上面几个例子可以看出:切割列表时,如果指定了stride,那么代码可能会变得相当费解。在一对中括号里写上3个数字显得太过拥挤,从而导致代码难以阅读。这种写法使得start和end索引的含义变得模糊,当stride为负值时,尤其如此。
为了解决这种问题,我们不应该把stride与start和end写在一起。如果非要用stride,那就尽量采用正值,同时省略start和end索引。如果一定要配合start或end索引来使用stride,那么请考虑先做步进式切片,把切割结果赋给某个变量,然后在那个变量上面做第二次切割。

上面这种先做步进切割,再做范围切割的办法,会多产生一份原数据的浅拷贝。执行第一次切割操作时,应该尽量缩减切割后的列表尺寸。如果你所开发的程序对执行时间或内存用量的要求非常严格,以致不能采用两阶段切割法,那就请考虑Python内置的itertools模块。该模块中有个islide方法,这个方法不允许为start、end或stride指定负值(参见本书第46条)。
要点
既有start和end,又有stride的切割操作,可能会令人费解。
尽量使用stride为正数,且不带start或end索引的切割操作。尽量避免用负数做stride。
在同一个切片操作内,不要同时使用start、end和stride。如果确实需要执行这种操作,那就考虑将其拆解为两条赋值语句,其中一条做范围切割,另一条做步进切割,或考虑使用内置itertools模块中的islice。

上一篇:攻防世界-pwn-level3


下一篇:ARM架构下添加系统调用(与32位x86区别)