1
for a in sorted(arr):
    doSomething()

对比

sArr = sorted(arr)
for a in sArr:
    doSomething()

这两个是否完全相同,或者一个会消耗更多的 CPU 周期然后另一个?

意思是, sorted(arr) 在第一个示例中的每个循环都会被调用吗?

谢谢

4

4 回答 4

5

它们几乎相同。

文档说:

表达式列表被评估一次;它应该产生一个可迭代的对象。

因此,sorted()在上面的代码中,不会有多次调用的风险。

第一种形式仍然更好,因为它更短更简洁,并且可以更好地优化(因为解释器可以确定循环结束后排序列表完全超出范围)。

于 2013-01-25T13:18:12.983 回答
4

它们并不完全相同,但差异很小。如有疑问,请使用该dis模块找出:

>>> import dis
>>> def f():
...     for a in sorted(arr):
...         doSomething()
... 
>>> def g():
...     sArr = sorted(arr)
...     for a in sArr:
...         doSomething()
... 
>>> dis.dis(f)
  2           0 SETUP_LOOP              27 (to 30)
              3 LOAD_GLOBAL              0 (sorted)
              6 LOAD_GLOBAL              1 (arr)
              9 CALL_FUNCTION            1
             12 GET_ITER            
        >>   13 FOR_ITER                13 (to 29)
             16 STORE_FAST               0 (a)

  3          19 LOAD_GLOBAL              2 (doSomething)
             22 CALL_FUNCTION            0
             25 POP_TOP             
             26 JUMP_ABSOLUTE           13
        >>   29 POP_BLOCK           
        >>   30 LOAD_CONST               0 (None)
             33 RETURN_VALUE        
>>> dis.dis(g)
  2           0 LOAD_GLOBAL              0 (sorted)
              3 LOAD_GLOBAL              1 (arr)
              6 CALL_FUNCTION            1
              9 STORE_FAST               0 (sArr)

  3          12 SETUP_LOOP              21 (to 36)
             15 LOAD_FAST                0 (sArr)
             18 GET_ITER            
        >>   19 FOR_ITER                13 (to 35)
             22 STORE_FAST               1 (a)

  4          25 LOAD_GLOBAL              2 (doSomething)
             28 CALL_FUNCTION            0
             31 POP_TOP             
             32 JUMP_ABSOLUTE           19
        >>   35 POP_BLOCK           
        >>   36 LOAD_CONST               0 (None)
             39 RETURN_VALUE        

如您所见,该g()函数添加了一个STORE_FASTandLOAD_FAST操作。您还使用了更多的内存,因为已排序的结果会保留在sArr变量被清理之前,而在f()循环结束后可以立即清理已排序的结果。

执行函数CALL_FUNCTIONsorted()它只执行一次。

于 2013-01-25T13:20:42.983 回答
1

sorted()返回一个随后被迭代的对象。它只被调用一次。

于 2013-01-25T13:18:24.783 回答
0

和其他人说的一样。请记住,当有疑问时(尽管在这种情况下微不足道且显而易见),请始终在源代码上运行反汇编。或者,您可以通过 cProfile 运行它,即使反汇编不同,cProfile 也会对性能给出一个公平的概念

>>> def foo():
    total = 0
    arr = range(10000000,1,-1)
    for a in sorted(arr):
        total += a


>>> def bar():
    total = 0
    for a in sorted(range(10000000,1,-1)):
        total += a


>>> cProfile.run("bar()")
         5 function calls in 2.614 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    1.914    1.914    2.614    2.614 <pyshell#88>:1(bar)
        1    0.000    0.000    2.614    2.614 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.266    0.266    0.266    0.266 {range}
        1    0.434    0.434    0.434    0.434 {sorted}


>>> cProfile.run("foo()")
         5 function calls in 2.477 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    1.779    1.779    2.346    2.346 <pyshell#86>:1(foo)
        1    0.130    0.130    2.477    2.477 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.152    0.152    0.152    0.152 {range}
        1    0.415    0.415    0.415    0.415 {sorted}


>>> 

正如你会在这里观察到的

  1. 在这两种情况下,Sorted 只被调用一次
  2. 每种情况下有 5 个函数调用
  3. 它们的性能几乎相同。
于 2013-01-25T13:21:09.770 回答