Python any()+生成器表达式 [英] Python any() + generator expression

查看:151
本文介绍了Python any()+生成器表达式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据此处的博客文章,任何()+生成器表达式应该比for循环运行得更快,看起来他的推理是有道理的。

但是我试过使用这个方法尽管在其他函数上),但它似乎需要花费较长的时间来运行比明确的循环。

  def with_loop( a,b):在xrange(1,b)中x为

如果x * a%b == 1:return True
return False

def with_generator(a,b):
在xrange(1,b)中x返回any(x * a%b == 1)

基本上,代码循环遍历从1到 b 的所有数字,以查找数字 a 是否具有模逆。 p>

运行函数的次数是:
$ b $ $ p $ >> ;> from timeit import Timer as T
>>> T(lambda:with_generator(100,300))。repeat(number = 100000)
[3.4041796334919923,3.6303230626526215,3.6714475531563266]
>>> T(lambda:with_loop(100,300))。repeat(number = 100000)
[2.1977450660490376,2.2083902291327604,2.1905292602997406]
>>> T(lambda:with_generator(101,300))。repeat(number = 100000)
[1.213779524696747,1.2228346702509043,1.2216941170634072]
>>> T(lambda:with_loop(101,300))。repeat(number = 100000)
[0.7431202233722161,0.7444361146951906,0.7525384471628058]



with_generator(100,300)返回False,with_generator(101,300)返回True。

看起来,with_generator总是需要比with_loop运行更长的时间。是否有任何理由呢?

编辑:
是否有其他更短或更优雅的方式来重写with_loop,以便达到类似或更好的性能?

解决方案

上下文我认为


any()+生成器表达式应该比for循环运行得更快

表示任何不会产生所有的值,而是一个循环:

 >>> T(lambda:any([x * 101%300 == 1 xrange(1,300)]))。)repeat。(number = 100000)
[5.7612644951345935,5.742304846931542,5.746804810873488]
> ;>> T(lambda:any(x * 101%300 == 1 for x in xrange(1,300)))。repeat(number = 100000)
[2.1652204281427814,21640463131248886,2164674290446399]

所以引用并不意味着一个循环永远无法达到一个生成器的性能。



引用意味着一个循环通常会生成所有的元素,任何一个都不会使用所有的元素,而一个生成器只会生成任何使用的元素。



函数 with_loop 相当于生成器。所以你不能指望一个不同的行为。



更清楚地说:任何(循环) 任何(发生器)因为循环产生的一切。你的 with_loop 相当于任何(发生器)而不是任何(循环)

原始问题

 >>> (6.1,300))。repeat(number = 100000))
600043函数调用(600040原始调用)在6.133秒

订购者:标准名称

ncalls tottime percall cumtime percall文件名:lineno(函数)
3 0.000 0.000 0.000 0.000:0(追加)
6 0.000 0.000 0.000 0.000: 0(时钟)
3 0.000 0.000 0.000 0.000:0(禁用)
3 0.000 0.000 0.000 0.000:0(使能)
3 0.000 0.000 0.000 0.000:0(全局)
1 0.000 0.000 0.000 0.000:0(hasattr)
3 0.000 0.000 0.000 0.000:0(isenabled)
2 0.000 0.000 0.000 0.000:0(isinstance)
1 0.000 0.000 0.000 0.000:0范围)
1 0.005 0.005 0.005 0.005:0(setprofile)
300000 0.579 0.000 5.841 0.000< string>:1(< lambda>
(with_loop)
1 0.000 0.000 6.133 6.133 profile:0(with_loop)1(
300000 5.262 0.000 5.262 0.000< string> T(lambda:with_loop(101,300))。repeat(number = 100000))
0 0.000 0.000 profile:0(profiler)
1 0.000 0.000 0.000 0.000 timeit.py:121(__init__)
3 0.000 0.000 0.000 0.000 timeit.py:143(安装)
3 0.000 0.000 6.128 2.043 timeit.py:178(timeit)
1 0.000 0.000 6.128 6.128 timeit.py:201(重复)
1 0.000 0.000 0.000 0.000 timeit.py:94(_template_func)
3 0.287 0.096 6.128 2.043 timeit.py:96(内)


>> >
31500043函数调用(31500040原语调用)在70.531秒
$ b($) $ b订单:标准名称

ncalls tottime percall cumtime percall文件名:lineno(功能)
300000 30.898 0.000 67.590 0.000:0(任意)
3 0.000 0.000 0.000 0.000: 0(附加)
6 0.000 0.000 0.000 0.000:0(时钟)
3 0.000 0.000 0.000 0.000:0(禁用)
3 0.000 0.000 0.000 0.000:0(启用)
3 0.000 0.000 0.000 0.000:0(全球变量)
1 0.000 0.000 0.000 0.000:0(hasattr)
3 0.000 0.000 0.000 0.000:0(isenabled)
2 0.000 0.000 0.000 0.000:0 isinstance)
1 0.000 0.000 0.000 0.000:0(范围)
1 0.000 0.000 0.000 0.000:0(setprofile)
300000 0.667 (<模块>)
300000 1.629 0.000 69.555 0.000 gt ; 6(with_generator)
30600000 37.027 0.000 37.027 0.000 :7(< genexpr>)
1 0.000 0.000 70.531 70.531 profile:0(T:lambda_with_generator(101,300) ).repeat(number = 100000))
0 0.000 0.000 profile:0(profiler)
1 0.000 0.000 0.000 0.000 timeit.py:121(__init__)
3 0.000 0.000 0.000 0.000 timeit。 py:143(setup)
3 0.000 0.000 70.531 23.510 timeit.py:178(timeit)
1 0.000 0.000 70.531 70.531 timeit.py:201(重复)
1 0.000 0.000 0.000 0.000 timeit .py:94(_template_func)
3 0.309 0.103 70.531 23.510 timeit.py:96(内部)



打电话给ge如果你知道列表中有多少元素,那么你可以这样写: / p>

  l [0] * 101%300 == 1或l [1] * 101%300 == 1或l [2 ] * 101%300 == 1或.... 


According to the blog post here, an any() + generator expression should run quicker than a for loop, and it seems like his reasoning makes sense.

But I've tried to use this method (albeit on some other function), but it seems to take a longer time to run than an explicit for loop.

def with_loop(a, b):
    for x in xrange(1, b):
        if x * a % b == 1: return True
    return False

def with_generator(a, b):
    return any(x * a % b == 1 for x in xrange(1, b))

Basically the code loops through all the numbers from 1 to b to find whether the number a has a modular inverse.

The times I got from running the functions are:

>>> from timeit import Timer as T
>>> T(lambda : with_generator(100, 300)).repeat(number = 100000)
[3.4041796334919923, 3.6303230626526215, 3.6714475531563266]
>>> T(lambda : with_loop(100, 300)).repeat(number = 100000)
[2.1977450660490376, 2.2083902291327604, 2.1905292602997406]
>>> T(lambda : with_generator(101, 300)).repeat(number = 100000)
[1.213779524696747, 1.2228346702509043, 1.2216941170634072]
>>> T(lambda : with_loop(101, 300)).repeat(number = 100000)
[0.7431202233722161, 0.7444361146951906, 0.7525384471628058]

with_generator(100,300) returns False and with_generator(101,300) returns True.

It seems that with_generator always takes a longer time to run than with_loop. Is there any reason for this?

EDIT: Is there any other shorter or more elegant way of rewriting with_loop so that we achieve similar or better performance? Thanks!

解决方案

Context

I think that

any() + generator expression should run quicker than a for loop

means that any does not generate all values but a loop does:

>>> T(lambda : any([x * 101 % 300 == 1 for x in xrange(1, 300)])).repeat(number = 100000)
[5.7612644951345935, 5.742304846931542, 5.746804810873488]
>>> T(lambda : any(x * 101 % 300 == 1 for x in xrange(1, 300))).repeat(number = 100000)
[2.1652204281427814, 2.1640463131248886, 2.164674290446399]

So the quote does not mean that a loop can never achieve the performance of a generator.

The quote means that a loop usually generates all elements and any does not use all of them and a generator only generates the elements that any uses.

Your function with_loop is equivalent to the generator. So you can not expect a different behaviour.

To put it more clearly: any(loop) is slower than any(generator) because the loop generates everything. Your with_loop is equivalent to any(generator) and not to any(loop).

Original Question

>>> profile.run("""T(lambda : with_loop(101, 300)).repeat(number = 100000)""")
         600043 function calls (600040 primitive calls) in 6.133 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        3    0.000    0.000    0.000    0.000 :0(append)
        6    0.000    0.000    0.000    0.000 :0(clock)
        3    0.000    0.000    0.000    0.000 :0(disable)
        3    0.000    0.000    0.000    0.000 :0(enable)
        3    0.000    0.000    0.000    0.000 :0(globals)
        1    0.000    0.000    0.000    0.000 :0(hasattr)
        3    0.000    0.000    0.000    0.000 :0(isenabled)
        2    0.000    0.000    0.000    0.000 :0(isinstance)
        1    0.000    0.000    0.000    0.000 :0(range)
        1    0.005    0.005    0.005    0.005 :0(setprofile)
   300000    0.579    0.000    5.841    0.000 <string>:1(<lambda>)
      4/1    0.000    0.000    6.128    6.128 <string>:1(<module>)
   300000    5.262    0.000    5.262    0.000 <string>:1(with_loop)
        1    0.000    0.000    6.133    6.133 profile:0(T(lambda : with_loop(101, 300)).repeat(number = 100000))
        0    0.000             0.000          profile:0(profiler)
        1    0.000    0.000    0.000    0.000 timeit.py:121(__init__)
        3    0.000    0.000    0.000    0.000 timeit.py:143(setup)
        3    0.000    0.000    6.128    2.043 timeit.py:178(timeit)
        1    0.000    0.000    6.128    6.128 timeit.py:201(repeat)
        1    0.000    0.000    0.000    0.000 timeit.py:94(_template_func)
        3    0.287    0.096    6.128    2.043 timeit.py:96(inner)


>>> profile.run("""T(lambda : with_generator(101, 300)).repeat(number = 100000)""")
         31500043 function calls (31500040 primitive calls) in 70.531 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
   300000   30.898    0.000   67.590    0.000 :0(any)
        3    0.000    0.000    0.000    0.000 :0(append)
        6    0.000    0.000    0.000    0.000 :0(clock)
        3    0.000    0.000    0.000    0.000 :0(disable)
        3    0.000    0.000    0.000    0.000 :0(enable)
        3    0.000    0.000    0.000    0.000 :0(globals)
        1    0.000    0.000    0.000    0.000 :0(hasattr)
        3    0.000    0.000    0.000    0.000 :0(isenabled)
        2    0.000    0.000    0.000    0.000 :0(isinstance)
        1    0.000    0.000    0.000    0.000 :0(range)
        1    0.000    0.000    0.000    0.000 :0(setprofile)
   300000    0.667    0.000   70.222    0.000 <string>:1(<lambda>)
      4/1    0.000    0.000   70.531   70.531 <string>:1(<module>)
   300000    1.629    0.000   69.555    0.000 <string>:6(with_generator)
 30600000   37.027    0.000   37.027    0.000 <string>:7(<genexpr>)
        1    0.000    0.000   70.531   70.531 profile:0(T(lambda : with_generator(101, 300)).repeat(number = 100000))
        0    0.000             0.000          profile:0(profiler)
        1    0.000    0.000    0.000    0.000 timeit.py:121(__init__)
        3    0.000    0.000    0.000    0.000 timeit.py:143(setup)
        3    0.000    0.000   70.531   23.510 timeit.py:178(timeit)
        1    0.000    0.000   70.531   70.531 timeit.py:201(repeat)
        1    0.000    0.000    0.000    0.000 timeit.py:94(_template_func)
        3    0.309    0.103   70.531   23.510 timeit.py:96(inner)

To call the generator every time, 30600000 times, seems to be much slower than just a for loop.

If you know how many elements exist in a list then you can write this:

l[0] * 101 % 300 == 1 or l[1] * 101 % 300 == 1 or l[2] * 101 % 300 == 1 or ....

这篇关于Python any()+生成器表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆