>>> range(1,11)
给你
[1,2,3,4,5,6,7,8,9,10]
为什么不是1-11?
他们是否只是随意决定这样做,或者它有什么价值我没有看到?
答案 0 :(得分:206)
因为更常见的是调用range(0, 10)
返回[0,1,2,3,4,5,6,7,8,9]
,其中包含10个等于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开头调用范围,则可能需要定义自己的函数:
>>> def range1(start, end):
... return range(start, end+1)
...
>>> range1(1, 10)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
答案 1 :(得分:21)
独家范围确实有一些好处:
首先,range(0,n)
中的每个项目都是长度为n
的列表的有效索引。
同样range(0,n)
的长度为n
,而不是n+1
,其中包含范围。
答案 2 :(得分:19)
虽然这里有一些有用的算法解释,但我认为可能有助于添加一些简单的“现实生活”推理,说明为什么它以这种方式工作,我发现在向年轻新人介绍这个主题时有用:
像“范围(1,10)”这样的东西可能会因为认为这对参数代表“开始和结束”而产生混淆。
实际上是开始并“停止”。
现在,如果 是 的“结束”值,那么,是的,您可能希望该数字将作为序列中的最终条目包含在内。但这不是“结束”。
其他人错误地将该参数称为“count”,因为如果你只使用'range(n)'那么它当然会迭代'n'次。添加start参数时,此逻辑会中断。
所以关键是要记住它的名字:“停止”。 这意味着,当达到时,迭代将立即停止。 之后
。因此,虽然“开始”确实代表了要包含的第一个值,但在达到“停止”值时,它“打破”而不是在停止之前继续处理“那个”。
我用来向孩子们解释这个问题的一个类比是,具有讽刺意味的是,它比孩子更好!它不会在之后停止它会立即停止而不会完成它正在做的事情。 (他们得到了这个;))
另一个比喻 - 当你驾驶汽车时,你没有 传递 停止/收益/'让路'的标志,并最终坐在旁边的某个地方,或后面,你的车。从技术上讲,当你停下来时,你仍然没有达到它。它不包括在“你旅行中传递的东西”中。
我希望其中一些有助于向Pythonitos / Pythonitas解释!
答案 3 :(得分:18)
与零基索引和len()
结合使用效果很好。例如,如果列表x
中有10个项目,则编号为0-9。 range(len(x))
为您提供0-9。
当然,人们会告诉你,for item in x
或for index, item in enumerate(x)
而不是for i in range(len(x))
更像是Pythonic。
切片也是如此:foo[1:4]
是foo
的第1-3项(请记住,由于从零开始的索引,第1项实际上是第2项)。为了保持一致性,它们应该以相同的方式工作。
我认为它是:“你想要的第一个号码,然后是不想要的第一个号码。”如果你想要1-10,你不想要的第一个数字是11,所以它是range(1, 11)
。
如果在特定的应用程序中变得很麻烦,那么编写一个小的辅助函数就很容易了,它会在结束索引中加1并调用range()
。
答案 4 :(得分:11)
范围的长度是最高值减去最低值。
它非常类似于:
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
答案 5 :(得分:11)
它对于分割范围也很有用; range(a,b)
可以分为range(a, x)
和range(x, b)
,而在包含范围的情况下,您可以编写x-1
或x+1
。虽然您很少需要拆分范围,但您确实倾向于经常拆分列表,这是切片列表l[a:b]
包括第a个元素而不是第b个元素的原因之一。然后具有相同属性的range
使其非常一致。
答案 6 :(得分:4)
考虑代码
for i in range(10):
print "You'll see this 10 times", i
这个想法是你得到一个长度y-x
的列表,你可以(如上所述)迭代。
在the python docs上读取范围 - 他们认为for循环迭代是主要用例。
答案 7 :(得分:4)
基本上在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()
答案 8 :(得分:1)
在许多情况下进行推理就更方便了。
基本上,我们可以将范围视为start
和end
之间的间隔。如果为start <= end
,则它们之间的间隔长度为end - start
。如果实际上将len
定义为长度,那么您将:
len(range(start, end)) == start - end
但是,我们计算范围内包含的整数,而不是测量间隔的长度。为了使上述属性为真,我们应包括一个端点,而排除另一个端点。
添加step
参数就像引入长度单位一样。在这种情况下,您会期望
len(range(start, end, step)) == (start - end) / step
长度。要获得计数,您只需使用整数除法即可。
答案 9 :(得分:0)
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