Effective Python(6): 单次切片操作,不要同时

2019-09-29  本文已影响0人  warmsirius

一、stride参数

除了基本的切片操作(参考Effective Python(5): 了解切割序列的方法), Python还提供了somelist[start:end:stride]形式的写法,以实现步进式切割。

例如:

a = ["red", "orange", "yellow", "green", "blue", "purple"]
odds = a[::2]
evens = a[1::2]
print(odds)
print(evens)

# Results
['red', 'yellow', 'blue']
['orange', 'green', 'purple']

二、问题

问题在于,采用stride方式进行切片时,经常会出现不符合预期的结果。

1. Python中有一个技巧,利用-1做步进值,可以将以字节形式存储的字符串反转过来

>>> x = b'diagnosor'
>>> y = x[::-1]
>>> y
b'rosongaid'

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

>>> w = '谢谢'
>>> x = w.encode('utf8')
>>> x
b'\xe8\xb0\xa2\xe8\xb0\xa2'
>>> y = x[::-1]
>>> y
b'\xa2\xb0\xe8\xa2\xb0\xe8'

>>> y.decode('utf8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xa2 in position 0: invalid start byte

2. 步长举例

a = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
a[::2]        # ['a', 'c', 'e', 'g']
a[::-2]       # ['h', 'f', 'd', 'b']

a[2::2]       # ['c', 'e', 'g']
a[-2::-2]     # ['g', 'e', 'c', 'a']
a[-2:2:-2]   # ['g', 'e']
a[2:2:-2]    # []

通过上面例子可以看出:切割列表时,如果指定了stride,那么代码可能会变得相当费解。在一对括号中写上3个数字显得太过拥挤,导致代码难以阅读。

解决:

b = a[::2]
c = b[1:-1]

这种先做步进切割,再做范围切割的办法,会多产生一份原数据的浅拷贝。执行第一次切割操作时,应该尽量缩减切割后的列表尺寸。

注意:
如果开发程序对执行时间或内存用量的要求非常严格,以致不能采用两阶段切割法,那就考虑Python内置的itertools模块中的islice方法,这个方法不允许为 startendstride指定负值。

三、要点

上一篇下一篇

猜你喜欢

热点阅读