for a in sorted(arr):
doSomething()
vs
sArr = sorted(arr)
for a in sArr:
doSomething()
これらの2つはまったく同じですか、それとも一方が他方よりも多くのCPUサイクルを消費しますか?
つまり、sorted(arr)は、最初の例のすべてのループで呼び出されますか?
ありがとう
for a in sorted(arr):
doSomething()
vs
sArr = sorted(arr)
for a in sArr:
doSomething()
これらの2つはまったく同じですか、それとも一方が他方よりも多くのCPUサイクルを消費しますか?
つまり、sorted(arr)は、最初の例のすべてのループで呼び出されますか?
ありがとう
それらはほとんど同じです。
ドキュメントには次のように書かれています。
式リストは1回評価されます。反復可能なオブジェクトを生成する必要があります。
sorted()
したがって、上記のコードでは、呼び出しが複数回発生するリスクはありません。
最初の形式は、短くて簡潔であるため、さらに優れており、最適化が可能になる可能性があります(ループの終了後に、ソートされたリストが完全にスコープ外になることを解釈者が判断できるため)。
まったく同じではありませんが、違いはごくわずかです。疑わしい場合は、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_FAST
LOAD_FAST
sArr
f()
関数CALL_FUNCTION
を実行します。sorted()
一度だけ実行されます。
sorted()
その後繰り返されるオブジェクトを返します。一度だけ呼び出されます。
他の人が言っているのと同じです。疑わしい場合は(この場合は些細で明白ですが)、常にソースに対して逆アセンブルを実行することを忘れないでください。または、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}
>>>
ここで観察するように