为什么切片和范围上限独占?为什么切片和范围上限独占?(Why are slice and range

2019-06-14 16:28发布

免责声明:我不是问如果上限stop的论点slice()range()是异或如何使用这些功能。

呼叫的rangeslice功能,以及切片标志[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?