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

vs

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

これらの2つはまったく同じですか、それとも一方が他方よりも多くのCPUサイクルを消費しますか?

つまり、sorted(arr)は、最初の例のすべてのループで呼び出されますか?

ありがとう

4

4 に答える 4

5

それらはほとんど同じです。

ドキュメントには次のように書かれています。

式リストは1回評価されます。反復可能なオブジェクトを生成する必要があります。

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_FASTLOAD_FASTsArrf()

関数CALL_FUNCTIONを実行します。sorted()一度だけ実行されます。

于 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は1回だけ呼び出されます
  2. いずれの場合も5つの関数呼び出しがあります
  3. それらはほぼ同じパフォーマンスを持っています。
于 2013-01-25T13:21:09.770 に答える