【Python 秘籍】对切片命名

问题

我们的代码已经变得无法阅读,到处都是切片索引,我们想将它们清理干净。

解决方案

假设有一些代码用来从字符串的固定位置中取出具体的数据:

record = '....................100.......513.25............'
cost = int(record[20:32] * float(record[40:48]))

与其这样做,不如对切片进行命名:

SHARES = slice(20, 32)
PRICE = slice(40, 48)
cost = int(record[SHARES]) * float(record[PRICE])

在后一种版本中,由于避免了使用许多神秘难懂的切片索引,我们的代码变得清晰了很多。

讨论

作为一条基本准则,代码中如果有很多序列的切片索引,将导致可读性和可维护性都不佳。例如,如果一年以后再回过头来看代码,你会发现自己很想直到当初编写这些代码时自己在想些什么。前面展示的方法可以让我们对代码的功能有着更加清晰的认识。

一般来说,内置的 slice() 函数会创建一个切片对象,可以用在任何允许进行切片操作的地方。例如:

>>> items = [0, 1, 2, 3, 4, 5, 6]
>>> a = slice(2, 4)
>>> items[2:4]
[2, 3]
>>> items[a]
[2, 3]
>>> items[a] = [10, 11]
>>> items
[0, 1, 10, 11, 4, 5, 6]
>>> del items[a]
>>> items
[0, 1, 4, 5, 6]

如果有一个 slice 对象的实例 s,可以分别通过 s.start、s.stop 以及 s.step 属性来得到关于该对象的信息。例如:

>>> a = slice(10, 50, 2)
>>> a.start
10
>>> a.stop
50
>>> a.step
2

此外,可以通过使用 indices(size)方法将切片映射到特定大小的序列上。这会返回一个 (start, stop, step) 元组,所有的值都已经恰当地限制在边界以内(当做索引操作时可避免出现 IndexError 异常)。例如:

>>> s = 'HelloWorld'
>>> a = slice(5, 50, 2)
>>> a.indices(len(s))
(5, 10, 2)
>>> for i in range(*a.indices(len(s))):
...     print(s[i])
...
W
r
d
>>>