原文请见 http://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html 著名计算机科学家Edsger W. Dijkstra的一篇备忘录,解释了为什么今天很多编程语言的Sequence对象的索引起点是0,而不是直觉上的1。
《流畅的Python》一书里推荐阅读该文,我就读了下,里面有很多梗我英语太差,读不懂,不过,备忘录所表达的意思,我大概是看明白了。
我们知道Python的序列索引从0开始的,很多其他语言也是如此,但我们数数总是从1开始,所以这个设定就有点反直觉。
在解释这个问题之前,Dijkstra首先解释了我们在序列切片时的规则——第一个数字包含在序列中,第二个数字不包含——这个规则是怎么被建议出来的。
如果我们要表示2,3,...12这串数字,我们有几如下几个表示法——
a)2 ≤ i < 13
b)1 < i ≤ 12
c)2 ≤ i ≤ 12
d)1 < i < 13
如果设这串数字的起始数字为x,结束数字为y,其实就是——
a)x ≤ i < y+1
b)x-1 < i ≤ y
c)x ≤ i ≤ y
d)x-1 < i < y+1
先比较x ≤ i和x-1 < i ,如果x = 0,那么为了表示从0开始的一串数字,x-1 < i表示法就变成了-1 < i,超出了自然数的范围,非常的ugly。
所以,x-1 < i输了,我们应该选择x ≤ i 。
再比较i < y+1和i ≤ y ,如果我们要表示一个空序列,也就是x = y,那么i ≤ y写出来就会非常奇怪,比如会写成1 ≤ i ≤ 1 ,也非常的ugly。
所以应该选择i < y+1
于是,表示一个序列的方法就默认为了x ≤ i < y+1
这就是序列切片的规则,第一个数字包含在序列中,第二个数字不包含。
有了序列表示的规则,Dijkstra解释了为什么序列起始数字是0,而不是1。根据上述规则,如果序列长度为N,起始数字为1,就得表示为——
1 ≤ i < N+1
因为最后一个数字不包含嘛。
这样一来对于长度为14的序列,我们必须表示为
1 ≤ i < 15
而如果起始数字为0,则表示为
0 ≤ i < N
同样长度为14的序列,就可以表示为
0 ≤ i < 14
14并没有包含在序列中,但14恰好代表了序列中元素的个数。So let us let our ordinals start at zero: an element's ordinal (subscript) equals the number of elements preceding it in the sequence.
这就是设置为0的好处。它和表示序列的方法是依赖的。由于不希望表示序列时出现超出自然数的情况,于是x ≤ i,而由于在空序列时,i ≤ y 看起来很奇怪,所以选择了i < y+1。
在这个序列表示法的前提之下,起始数字为0, 则y+1就是序列的长度N......数字0真神奇!after all those centuries!— zero as a most natural number.
起始索引为0,于是我们在对一个序列对象作切片操作[:y]的时候,y即为对象的数量,同样的[x:y]返回的对象的数量刚好是y-x。