Python:为什么`random.randint(a, b)`返回包含`b`的范围?
我一直觉得很奇怪,为什么 random.randint(a, b)
会返回一个在 [a, b]
范围内的整数,而不是像 range(...)
那样返回 [a, b-1]
的范围。
这看起来有点不一致,是不是有什么特别的原因呢?
4 个回答
这只是个人猜测,但一般人说“给我一个从a到b的随机数”时,通常是包括a和b这两个数字的。这样实现其实挺合理的,因为Python的设计理念就是让代码更容易被人理解。
我想 random.randint
只是实现这个功能的第一次尝试。看起来Python的开发者也觉得这个有问题,所以在版本1.5.2的时候,他们增加了另一个方法 randrange,这个方法的参数更标准:
random.randrange([start], stop[, step])
这个方法会从指定的范围(开始值、结束值和步长)中随机选择一个元素。它的效果和
choice(range(start, stop, step))
是一样的,但它并不会实际创建一个范围对象。
你可以用 randrange
来代替 randint
,这样可以避免让人感到意外。
另一方面,在很多情况下,如果问题是“选择一个1到6之间的随机数”,用 randint(1, 6)
可能会更自然,而不是写 randrange(1, 7)
或 randrange(min, max + 1)
。
我试着通过查看一些旧的资料来搞清楚这个问题。我怀疑,randint
是在Python的长整型之前实现的。这意味着如果你想要一个包含INT_MAX
的随机数,你就需要调用random.randrange(0, INT_MAX + 1)
,这会导致溢出,结果可能会变成(0, 0)
或者(0, INT_MIN)
,具体取决于情况。
不过,追溯到甚至是Python 1.5.2的源代码,在Lib/whrandom.py
中我们可以看到:
#
# Get a random integer in the range [a, b] including both end points.
# (Deprecated; use randrange below.)
#
def randint(self, a, b):
return self.randrange(a, b+1)
whrandom.randint
在2.0、2.1、2.2和2.3中继续被弃用;但是random.randint
在2.1中被标记为弃用,不过在2.2中又不再被标记为弃用。
另外,random.py
在2.1版本中是第一个在random.randint
的文档字符串中提到的:
def randrange(self, start, stop=None, step=1, int=int, default=None):
"""Choose a random item from range(start, stop[, step]).
This fixes the problem with randint() which includes the
endpoint; in Python this is usually not what you want.
Do not supply the 'int' and 'default' arguments.
"""
在这之前唯一可用的源代码是0.9.1版本的源代码,据我所知,那个时候randint
并没有实现。
因此,我得出的结论是,randint
包含结束点的原因目前只有Guido自己知道;根据Python 2.1的文档字符串,听起来这个原因可能只是一个简单的错误。