为什么范围(开始,结束)不包括结束?

>>> range(1,11)

给你

[1,2,3,4,5,6,7,8,9,10]

为什么不是1-11?

他们是随机决定这么做的还是有我看不到的价值?

445103 次浏览

因为调用range(0, 10)更常见,它返回包含10个元素的[0,1,2,3,4,5,6,7,8,9],等于len(range(0, 10))。记住,程序员更喜欢基于0的索引。

另外,考虑下面的公共代码片段:

for i in range(len(li)):
pass

你能看出,如果range()恰好上升到len(li),这将是有问题的?程序员需要显式地减去1。这也符合程序员更喜欢for(int i = 0; i < 10; i++)而不是for(int i = 0; i <= 9; i++)的普遍趋势。

如果你频繁调用起始值为1的range,你可能需要定义自己的函数:

>>> def range1(start, end):
...     return range(start, end+1)
...
>>> range1(1, 10)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

范围的长度是上值减去下值。

它非常类似于:

for (var i = 1; i < 11; i++) {
//i goes from 1 to 10 in here
}

c风格的语言。

也像Ruby的范围:

1...11 #this is a range from 1 to 10

然而,Ruby意识到很多时候你想要包含终端值,并提供了另一种语法:

1..10 #this is also a range from 1 to 10

专属范围确实有一些好处:

首先,range(0,n)中的每一项都是长度为n的列表的有效索引。

而且range(0,n)的长度是n,而不是包含范围的n+1

它与从零开始的索引和len()结合使用效果很好。例如,如果在列表x中有10个项目,它们的编号为0-9。range(len(x))给出0-9。

当然,人们会告诉你,执行for item in xfor index, item in enumerate(x)比执行for i in range(len(x))更python化。

切片也是这样工作的:foo[1:4]foo的第1-3项(请记住,由于从零开始的索引,第1项实际上是第二项)。为了保持一致性,它们应该以相同的方式工作。

我认为它是:“你想要的第一个数字,后面跟着你想要的第一个数字。”如果你想要1-10,你不想要的第一个数字是11,所以它是range(1, 11)

如果它在特定的应用程序中变得很麻烦,那么很容易编写一个小的帮助函数,将1添加到结束索引并调用range()

考虑代码

for i in range(10):
print "You'll see this 10 times", i

这个想法是你得到一个长度为y-x的列表,你可以(如上所述)迭代它。

仔细阅读python文档中的range -他们认为for循环迭代是主要的用例。

它对于分割范围也很有用;range(a,b)可以分为range(a, x)range(x, b),而对于包含范围,你可以写x-1x+1。虽然你很少需要分割范围,但你确实倾向于经常分割列表,这是切片列表l[a:b]包含第a个元素而不包括第b个元素的原因之一。那么range具有相同的属性使得它很好地一致。

虽然这里有一些有用的算法解释,但我认为它可能有助于添加一些简单的“现实生活”推理,以解释为什么它是这样工作的,在向年轻的新人介绍这个主题时,我发现这很有用:

对于像“range(1,10)”这样的东西,可能会因为认为参数对代表“开始和结束”而产生混淆。

它实际上是开始和“停止”。

现在,如果它< em > < / em >“end”值,那么,是的,你可能会期望这个数字将被包括在序列的最后一项。但这并不是“结束”。

其他人错误地称该参数为“count”,因为如果你只使用“range(n)”,那么它当然会迭代“n”次。当添加start参数时,这种逻辑就失效了。

所以关键是要记住它的名字:"停止"。 这意味着当到达这个点时,迭代将立即停止。而不是< em > < / em >后那个点

因此,虽然“start”确实表示要包含的第一个值,但在达到“stop”值时,它会“中断”,而不是在停止之前继续处理“那个值”。

我在向孩子们解释这一点时用的一个比喻是,具有讽刺意味的是,他们比孩子们表现得更好!它不会停止——它会在没有完成它正在做的事情之前立即停止。(他们得到了这个;))

另一个类比——当你开车时,你没有< em > < /通过em >一个停止/让行/“让路”的标志,结果它坐在你车旁边或后面的某个地方。从技术上讲,当你停下来时,你还没有到达它。它不包括在“你旅途中经过的东西”中。

我希望其中一些有助于向Pythonitos/Pythonitas解释!

基本上在python中range(n)迭代n次,这是排他的性质,这就是为什么它在被打印时不给出最后一个值,我们可以创建一个函数,给出 包含值,这意味着它还将打印范围内提到的最后一个值
def main():
for i in inclusive_range(25):
print(i, sep=" ")




def inclusive_range(*args):
numargs = len(args)
if numargs == 0:
raise TypeError("you need to write at least a value")
elif numargs == 1:
stop = args[0]
start = 0
step = 1
elif numargs == 2:
(start, stop) = args
step = 1
elif numargs == 3:
(start, stop, step) = args
else:
raise TypeError("Inclusive range was expected at most 3 arguments,got {}".format(numargs))
i = start
while i <= stop:
yield i
i += step




if __name__ == "__main__":
main()

只是在很多情况下更方便推理。

基本上,我们可以认为范围是startend之间的间隔。如果start <= end,则它们之间的间隔长度为end - start。如果len实际上被定义为长度,你会得到:

len(range(start, end)) == start - end

但是,我们计算范围中包含的整数,而不是测量间隔的长度。为了保持上述性质为真,我们应该包括其中一个端点并排除另一个端点。

添加step形参就像引入一个长度单位。在这种情况下,你会期望

len(range(start, end, step)) == (start - end) / step

的长度。要得到计数,只需使用整数除法。

python中的range(n)返回从0到n-1的值。分别为range(1,n)从1到n-1。 因此,如果你想省略第一个值,并获得最后一个值(n),你可以使用以下代码非常简单地做到这一点
for i in range(1, n + 1):
print(i) #prints from 1 to n