繁体   English   中英

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

[英]Shorter runtime of `random.shuffle` when using `random.random` as keyword argument in Python3

我刚刚观察到,当使用Python3显式提交random关键字参数的函数random.random ,对random.shuffle的列表进行random.shuffle大约需要运行时间的一半。 我检查了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))

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

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

我在Lib/random.py文件夹中检查了各自的源(Python2与Python3)中的shuffle函数,发现如果我使用random关键字的函数显式调用Python3版本,它们的行为方式相同。 如果我忽略此参数,Python3将使用辅助函数_randbelow因此应该是我的问题的根源。 我看不到Python3为什么使用_randbelow因为它会减慢shuffle速度。 据我所知,它的好处在于生成任意大的随机数,但是它不会减慢我对列表少于2 ^ 32个元素(在我的情况下为100000)的列表的拖曳。

谁能向我解释为什么我在运行时看到这样的差异,尽管在使用Python3时它们应该靠得更近些?

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

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

    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]

但是在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]

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM