在Python3中使用`random.random`作为关键字参数时,`random.shuffle`的运行时间更短

hal*_*lex 8 python random runtime shuffle python-3.x

我观察到,当使用Python3洗牌名单与random.shuffle需要大约一半的运行时,明确地提交功能random.randomrandom关键字参数.我检查了Python2是否有同样的问题,但发现它只发生在Python3上.

我使用以下代码来测量两个版本的运行时间:

from timeit import Timer
t1 = Timer("random.shuffle(l)", "import random; l = list(range(100000))")
t2 = Timer("random.shuffle(l, random = random.random)", "import random; l = list(range(100000))")
print("With default rand: %s" % t1.repeat(10,1))
print("With custom rand: %s" % t2.repeat(10,1))
Run Code Online (Sandbox Code Playgroud)

我做了一个在ideone测试用例,为您与Python3和相同的代码中看到Python2.

根据shuffle文档,random.random当我省略可选关键字参数时,在默认情况下使用相同的函数random,因此当我给它生成与默认情况下的随机数相同的函数时应该没有区别.

我检查了文件夹中shuffle函数的相应源(Python2与Python3)Lib/random.py,发现如果我使用random关键字函数显式调用Python3版本,它们的行为方式相同.如果我省略这个参数,Python3使用辅助函数,_randbelow所以应该有我的问题的根.我不明白为什么Python3会使用_randbelow它,因为它会变慢shuffle.据我了解,它的好处在于生成任意大的随机数,但它不应该减慢我的一个列表的速度,这个列表的次数少于2 ^ 32个元素(在我的情况下为100000).

任何人都可以向我解释为什么我在运行时看到这样的差异,虽然我使用Python3时它们应该更加接近?

PS:请注意,我不感兴趣为什么Python2的运行时比Python3好,但是rand=rand.rand在Python3中使用参数参数而不是仅在Python3中使用它时运行时的差异.

Sch*_*huh 4

函数中的文档字符串random.shuffle与代码相矛盾。在 python 2.7.2+ 中,文档字符串是正确的:

    def shuffle(self, x, random=None, int=int):
    """x, random=random.random -> shuffle list x in place; return None.

    Optional arg random is a 0-argument function returning a random
    float in [0.0, 1.0); by default, the standard random.random.
    """

    if random is None:
        random = self.random
    for i in reversed(xrange(1, len(x))):
        # pick an element in x[:i+1] with which to exchange x[i]
        j = int(random() * (i+1))
        x[i], x[j] = x[j], x[i]
Run Code Online (Sandbox Code Playgroud)

但在 Python 3.2 中我们发现:

def shuffle(self, x, random=None, int=int):
    """x, random=random.random -> shuffle list x in place; return None.

    Optional arg random is a 0-argument function returning a random
    float in [0.0, 1.0); by default, the standard random.random.
    """

    randbelow = self._randbelow
    for i in reversed(range(1, len(x))):
        # pick an element in x[:i+1] with which to exchange x[i]
        j = randbelow(i+1) if random is None else int(random() * (i+1))
        x[i], x[j] = x[j], x[i]
Run Code Online (Sandbox Code Playgroud)

所以文档字符串仍然讲述旧故事,但现在使用的默认函数是 random.randbelow