Python:为什么`random.randint(a, b)`返回包含`b`的范围?

63 投票
4 回答
74191 浏览
提问于 2025-04-15 21:10

我一直觉得很奇怪,为什么 random.randint(a, b) 会返回一个在 [a, b] 范围内的整数,而不是像 range(...) 那样返回 [a, b-1] 的范围。

这看起来有点不一致,是不是有什么特别的原因呢?

4 个回答

10

这只是个人猜测,但一般人说“给我一个从a到b的随机数”时,通常是包括a和b这两个数字的。这样实现其实挺合理的,因为Python的设计理念就是让代码更容易被人理解。

16

我想 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)

100

我试着通过查看一些旧的资料来搞清楚这个问题。我怀疑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.randint2.02.12.22.3中继续被弃用;但是random.randint2.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的文档字符串,听起来这个原因可能只是一个简单的错误。

撰写回答