2013-08-05 12 views
5

Kiedy zmieniłw Pythonie, dlaczego jeśli rank: jest szybsze niż w przypadku ranga = 0:

for i in range(0, 100): 
    rank = ranks[i] 
    if rank != 0: 
     pass 

do:

for i in range(0, 100): 
    rank = ranks[i] 
    if rank: 
     pass 

znalazłem drugi kod jest znacznie bardziej wydajny, dlaczego?

znak ława to, w mojej sytuacji szeregach jest numpy tablicę liczb całkowitych. Różnica jest znacznie większa.

import numpy as np 
import time 
N = 1000000 
ranks = np.random.random_integers(0, 10, N) 
start = time.time() 
for i in range(0, N): 
    rank = ranks[i] 
    if rank != 0: 
     pass 

print time.time() - start 
start = time.time() 
for i in range(0, N): 
    rank = ranks[i] 
    if rank: 
     pass 
print time.time() - start 
start = time.time() 
for i in range(0, N): 
    if i != 0: 
     pass 

print time.time() - start 
start = time.time() 
for i in range(0, N): 
    if i: 
     pass 
print time.time() - start 

wyjściowa:

1.15917396545 
0.45020198822 
0.123136997223 
0.122531175613 
+7

skąd można zauważyć, że? czy porównałeś to? – zsong

+0

Spodziewałbym się pewnego przyspieszenia, ponieważ w interpretowanym języku Python jest mniej pracy, a więcej dzieje się we wbudowanych metodach, ale w prawdziwym programie prawdopodobnie nie byłaby duża. (Nadal warto to robić, ponieważ jest to standardowy styl i mniej kodu.) – user2357112

Odpowiedz

8

destylacji kontrole do rdzenia

for i in range(0,100): 
    if i != 0: 
    pass 

i

for i in range(0,100): 
    if i: 
    pass 

Widzimy istnieje różnica

$ python -m timeit 'for i in range(0,100):' ' if i != 0:' ' pass' 
100000 loops, best of 3: 4.69 usec per loop 
$ python -m timeit 'for i in range(0,100):' ' if i:' ' pass' 
100000 loops, best of 3: 4.18 usec per loop 

Różnica polega na tym, że podczas gdy pierwszy przypadek polega na porównaniu do zera, drugi przypadek po prostu sprawdza, czy fałszywe.

Aby zobaczyć, co robi, użyj dis:

>>> def f(): 
... for i in range(0,100): 
... if i: 
...  pass 
... 
>>> def g(): 
... for i in range(0,100): 
... if i != 0: 
...  pass 
... 
>>> from dis import dis 
>>> dis(f) 
    2   0 SETUP_LOOP    32 (to 35) 
       3 LOAD_GLOBAL    0 (range) 
       6 LOAD_CONST    1 (0) 
       9 LOAD_CONST    2 (100) 
      12 CALL_FUNCTION   2 
      15 GET_ITER 
     >> 16 FOR_ITER    15 (to 34) 
      19 STORE_FAST    0 (i) 

    3   22 LOAD_FAST    0 (i) 
      25 POP_JUMP_IF_FALSE  16 

    4   28 JUMP_ABSOLUTE   16 
      31 JUMP_ABSOLUTE   16 
     >> 34 POP_BLOCK 
     >> 35 LOAD_CONST    0 (None) 
      38 RETURN_VALUE 
>>> dis(g) 
    2   0 SETUP_LOOP    38 (to 41) 
       3 LOAD_GLOBAL    0 (range) 
       6 LOAD_CONST    1 (0) 
       9 LOAD_CONST    2 (100) 
      12 CALL_FUNCTION   2 
      15 GET_ITER 
     >> 16 FOR_ITER    21 (to 40) 
      19 STORE_FAST    0 (i) 

    3   22 LOAD_FAST    0 (i) 
      25 LOAD_CONST    1 (0) <-- this only happens in != 0 
      28 COMPARE_OP    3 (!=) <-- this only happens in != 0 
      31 POP_JUMP_IF_FALSE  16 

    4   34 JUMP_ABSOLUTE   16 
      37 JUMP_ABSOLUTE   16 
     >> 40 POP_BLOCK 
     >> 41 LOAD_CONST    0 (None) 
      44 RETURN_VALUE 
+0

Moja sytuacja, rangi to szereg liczb całkowitych. Wydaje się, że różnica jest znacznie większa. – BerSerK

+0

Jeśli "wyłączysz" obie próbki, różnica nadal będzie mieć wartość "LOAD_CONST 1 (0)" i "COMPARE_OP 3 (! =)". – SheetJS

+0

, ale jak wyjaśnić, czy zastąpisz 'if' z' i == True'? ten ostatni jest nawet wolniejszy – zsong

Powiązane problemy