发电机与Python中的列表理解性能



目前我正在学习生成器和列表理解力,并与profiler弄乱,以查看偶然发现的性能提升,偶然发现了使用两者都在较大范围内的质量数量的cprofile。/p>

我可以在发电机中看到:1 genexpr比其列表中的累积时间短,但第二行是让我感到困惑的。我认为数字的支票是素数是素数的,但是不应该是另一个:列表中的1个模块?

我在个人资料中缺少某些内容吗?

In [8]: cProfile.run('sum((number for number in xrange(9999999) if number % 2 == 0))')
         5000004 function calls in 1.111 seconds
   Ordered by: standard name
   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
  5000001    0.760    0.000    0.760    0.000 <string>:1(<genexpr>)
        1    0.000    0.000    1.111    1.111 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.351    0.351    1.111    1.111 {sum}

In [9]: cProfile.run('sum([number for number in xrange(9999999) if number % 2 == 0])')
         3 function calls in 1.123 seconds
   Ordered by: standard name
   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    1.075    1.075    1.123    1.123 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.048    0.048    0.048    0.048 {sum}

首先,所有调用是对 next(或python 3中的 __next__)的生成器对象的方法,而不是某些偶数数字检查。

在Python 2中,您不会为列表理解(LC)获得任何其他行,因为LC没有创建任何对象,但是在Python 3中,您会因为现在使其类似于生成器表达式一个附加代码对象(<listcomp>)也是为LC创建的。

>>> cProfile.run('sum([number for number in range(9999999) if number % 2 == 0])')
         5 function calls in 1.751 seconds
   Ordered by: standard name
   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    1.601    1.601    1.601    1.601 <string>:1(<listcomp>)
        1    0.068    0.068    1.751    1.751 <string>:1(<module>)
        1    0.000    0.000    1.751    1.751 {built-in method exec}
        1    0.082    0.082    0.082    0.082 {built-in method sum}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
>>> cProfile.run('sum((number for number in range(9999999) if number % 2 == 0))')
         5000005 function calls in 2.388 seconds
   Ordered by: standard name
   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
  5000001    1.873    0.000    1.873    0.000 <string>:1(<genexpr>)
        1    0.000    0.000    2.388    2.388 <string>:1(<module>)
        1    0.000    0.000    2.388    2.388 {built-in method exec}
        1    0.515    0.515    2.388    2.388 {built-in method sum}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

与发电机表达式中的5000001相比,调用数量不同,这是最大的,这是因为sum正在消耗迭代器,因此必须调用其__next__方法500000 1次(最后1个可能是StopIteration要结束迭代)。对于列表,理解所有魔法发生在其代码对象中,其中LIST_APPEND在其中一个将项目一个接一个地附加到列表中,即对cProfile的可见呼叫。

最新更新