免责声明:我不是问如果上限stop
的论点slice()
和range()
是异或如何使用这些功能。
呼叫的range
和slice
功能,以及切片标志[start:stop]
均指整数集。
range([start], stop[, step])
slice([start], stop[, step])
在所有这些,将stop
整数被排除在外。
我很奇怪,为什么语言是这样设计的。
是它作出stop
等于在时所表示的整数组元素的数量start
等于0或省略?
是不是有:
for i in range(start, stop):
看起来像下面的C代码?
for (i = start ; i < stop; i++) {
Answer 1:
该文件意味着这有几个有用的属性:
word[:2] # The first two characters
word[2:] # Everything except the first two characters
这里的切片操作有一个很有不变: s[:i] + s[i:]
等于s
。
对于非负索引,片段的长度是指数的差,如果两者界限内。 例如,长度word[1:3]
是2
。
我认为,我们可以假设范围内的功能作用相同的一致性。
Answer 2:
这里的观点有些Google+使用者的:
[...]我被半开区间的风采左右。 尤其是不变的,当两片相邻,第一片的最终指标是第二片的开始指数是太美丽的,不容忽视。 例如,假设您将一个字符串分解成索引三个部分i和j - 部分将是一个[我],A [1:J],以及[J:]。
Answer 3:
有点晚了这个问题,但是,这个试图回答为什么 -part你的问题:
部分原因是因为我们使用基于零的索引/偏移寻址内存时。
最简单的例子是一个数组。 认为一个以存储6个的数据项的位置“的第6项数组”的。 如果该数组的起始位置是在存储器地址100,则数据,让我们说的6个字符“苹果\ 0”,被存储这样的:
memory/
array contains
location data
100 -> 'a'
101 -> 'p'
102 -> 'p'
103 -> 'l'
104 -> 'e'
105 -> '\0'
因此,对于6项,我们的索引变为从正在使用基地产生的+偏移 100到105的地址,所以第一项是在基本存储器位置 100 + 偏移 0(即,100 + 0),则在100 + 1,第三第二在100 + 2,...,直到100 + 5的最后位置。
这是我们使用从零开始的索引的主要原因,并导致语言结构,例如for
用C循环:
for (int i = 0; i < LIMIT; i++)
或在Python:
for i in range(LIMIT):
当你在像C,你处理球更直接,或装配更是这样一个语言程序,这个基地+偏移方案变得更加明显。
因为以上所述,许多语言构造的自动使用该范围从开始到长度-1。
您可能会发现这篇文章的零基编号维基百科有趣,而且这个问题从软件工程SE 。
例如 :
在C例如,如果你有一个阵列ar
和你下标它作为ar[3]
这确实是相当于服用(碱)地址阵列的ar
和添加3
到它=> *(ar+3)
其可导致这样的代码印刷数组的内容,示出了简单的基+偏移量的方法:
for(i = 0; i < 5; i++)
printf("%c\n", *(ar + i));
真的等同于
for(i = 0; i < 5; i++)
printf("%c\n", ar[i]);
Answer 4:
这里的另一个原因是独特的上限是一个理智的做法:
假设你想编写应用一些转变为项目的子列表中的一个功能。 如果时间间隔分别为您建议使用一个具有包容性的上限,你可能会天真地尝试写它:
def apply_range_bad(lst, transform, start, end):
"""Applies a transform on the elements of a list in the range [start, end]"""
left = lst[0 : start-1]
middle = lst[start : end]
right = lst[end+1 :]
return left + [transform(i) for i in middle] + right
乍一看,这似乎简单,正确的,但不幸的是巧妙地错了。
会发生什么,如果:
-
start == 0
-
end == 0
-
end < 0
? 在一般情况下,有可能甚至,你应该考虑更多的边界情况。 谁愿意浪费时间去考虑这一切? (因为出现这些问题,通过使用包括上限和下限,也没有固有的方式来表达一个空的间隔 。)
取而代之的是,通过使用模型,其中上限是独占的,将一个列表到单独的片是更简单,更优雅,因而不易出错 :
def apply_range_good(lst, transform, start, end):
"""Applies a transform on the elements of a list in the range [start, end)"""
left = lst[0:start]
middle = lst[start:end]
right = lst[end:]
return left + [transform(i) for i in middle] + right
(请注意, apply_range_good
不变换lst[end]
;它也对待end
的专属的上限,试图让使用它的包容性上界仍然有一些我前面提到的问题寓意是,包容性上。 -bounds通常麻烦的。)
(大多改编自旧的文章有关其他脚本语言包括上界雷的 。)
Answer 5:
优雅的烦躁VS明显的烦躁
说实话,我觉得在Python切片的方式是非常反直觉的,它实际上是交易的所谓高雅的烦躁与更多的大脑处理,这就是为什么你可以看到这个StackOverflow的文章比upvotes的2KS多,我想这是因为有很多人不intially理解。
只是举例,下面的代码已经进行了大量的Python的新手造成的头痛。
x = [1,2,3,4]
print(x[0:1])
# Output is [1]
不仅是难以加工的同时,还很难进行适当的解释,例如,用于该代码的解释上面会采取第零个元素,直到所述第一元件之前的元素 。
现在看看红宝石它采用上限包容性。
x = [1,2,3,4]
puts x[0..1]
# Output is [1,2]
坦率地说,我真的以为切片的红宝石的方式对大脑更好。
当然,如果要拆分列表分为两个部分基于索引, 独家上限的做法将导致更好看代码。
# Python
x = [1,2,3,4]
pivot = 2
print(x[:pivot]) # [1,2]
print(x[pivot:]) # [3,4]
现在,让我们期待包容上限的方法
# Ruby
x = [1,2,3,4]
pivot = 2
puts x[0..(pivot-1)] # [1,2]
puts x[pivot..-1] # [3,4]
显然,代码是那么优雅,但有没有在这里做了很多大脑处理。
结论
最后,这真是一个关于优雅的烦躁VS明显的烦躁的事情,和Python的设计者更喜欢优雅的烦躁了明显的烦躁。 为什么? 由于Python的禅指出, 美比丑好 。
文章来源: Why are slice and range upper-bound exclusive?