第6条:在单次切片操作内,不要同时指定start、end和stride
核心知识点:
1.使用负步进可以反转取值字符串及ASCII。
2.stride最好不要与start和end用在一起,会降低代码可读性。
除了基本的切片操作之外,python还提供了somelist[start:end:stride]形式的写法,以实现步进式切割,也就是从每n个元素里面取一个出来。例如:
In [1]: a = [] In [2]: a = ['red','orange','yellow','green','blue','purple'] In [3]: odds = a[::2] In [4]: evens = a[1::2] In [5]: print(odds) ['red', 'yellow', 'blue'] In [6]: print(evens) ['orange', 'green', 'purple']
问题在于,采用stride方式切片,经常会出现不符合预期的结果。
例如,python中有一种常见的技巧,能够把以字节形式存储的字符串反转过来,这个技巧就是采用-1做步进值。
(关于-1反取,可参考博客:http://www.cnblogs.com/yangmingxianshen/p/7995234.html)
In [43]: x = b'mongoose' In [44]: y = x[::-1] In [45]: print(y) b'esoognom'
但是这种技巧对于字符串和ASCII字符有用,但是对于已经编码成为utf-8的unicode字符来说,则是无效的
In [46]: w = '你好' In [47]: x = w.encode('utf-8') In [48]: y = x[::-1] In [50]: z = y.decode('utf-8') --------------------------------------------------------------------------- UnicodeDecodeError Traceback (most recent call last) <ipython-input-50-7299a67a0700> in <module>() ----> 1 z = y.decode('utf-8') UnicodeDecodeError: 'utf-8' codec can't decode byte 0xbd in position 0: invalid start byte
除了-1之外,其他的负步进值有没有意义呢?
In [52]: a = ['a','b','c','d','e','f','g','h'] In [53]: a[::2] Out[53]: ['a', 'c', 'e', 'g'] In [54]: a[::-2] Out[54]: ['h', 'f', 'd', 'b']
负的步进值会从尾部开始取值。如果给出start和end会怎样?
In [55]: a[2::2] Out[55]: ['c', 'e', 'g'] In [56]: a[-2::2] Out[56]: ['g'] In [57]: a[-2::-2] Out[57]: ['g', 'e', 'c', 'a'] In [58]: a[-2:2:-2] Out[58]: ['g', 'e'] In [59]: a[2:2:-2] Out[59]: []
在切割列表的时候,如果指定了stride,那么代码可能会变得相当费解。
在一对括号里写上3个数字显得拥挤,从而使代码不易阅读,这样的写法使得start和end索引的含义变得模糊。
为了解决这种问题,我们不应该把stride与start和end写在一起。如果非要用stride,那就尽量采用正值。
如果一定要配合start和end,可以将步进切割和切片分开。
In [60]: b = a[::2] In [61]: c = b[1:-1] In [62]: print(c) ['c', 'e']
这种做法会产生一份浅拷贝数据,因此会带来额外的内存消耗。