2016-05-24 5 views
7

Il seguente frammento di codice crea e distrugge l'elenco di costanti su ciascun ciclo, incorrendo in qualsiasi carico (anche se piccolo) che questo implica, oppure l'elenco viene creato una sola volta?Un elenco costante viene utilizzato in un loop costruito/cancellato con ciascun passaggio?

for i in <some-type-of-iterable>: 
    if i in [1,3,5,18,3457,40567]: 
     print(i) 

sto chiedendo circa sia il Python "standard", come ad esempio uno come esiste, e circa l'applicazione comune CPython.
Sono consapevole che questo esempio è inventato, così come quello che cerca di preoccuparsi delle prestazioni usando CPython è sciocco, ma sono solo curioso.

+2

domande come questo sono ciò che 'dis' è fatto per! –

+0

La risposta sembra essere "no". – Jasper

risposta

2

Un altro esempio con Python 3.5, elenco viene creato per ogni iterazione.

>>> import dis 
>>> def func(): 
... for i in iterable: 
... for j in [1,2,3]: 
... print(i+j) 
... 
>>> dis.dis(func) 
    2   0 SETUP_LOOP    54 (to 57) 
       3 LOAD_GLOBAL    0 (iterable) 
       6 GET_ITER 
     >> 7 FOR_ITER    46 (to 56) 
      10 STORE_FAST    0 (i) 

    3   13 SETUP_LOOP    37 (to 53)  
      16 LOAD_CONST    1 (1)  # building list 
      19 LOAD_CONST    2 (2) 
      22 LOAD_CONST    3 (3) 
      25 BUILD_LIST    3 
      28 GET_ITER 
     >> 29 FOR_ITER    20 (to 52) # inner loop body begin 
      32 STORE_FAST    1 (j) 

    4   35 LOAD_GLOBAL    1 (print) 
      38 LOAD_FAST    0 (i) 
      41 LOAD_FAST    1 (j) 
      44 BINARY_ADD 
      45 CALL_FUNCTION   1 (1 positional, 0 keyword pair) 
      48 POP_TOP 
      49 JUMP_ABSOLUTE   29   # inner loop body end 
     >> 52 POP_BLOCK 
     >> 53 JUMP_ABSOLUTE   7   # outer loop end, 
               # jumping back before list creation 
     >> 56 POP_BLOCK 
     >> 57 LOAD_CONST    0 (None) 
      60 RETURN_VALUE 
+0

Quale lista stai dicendo viene creata una sola volta? Non sono esperto nella lettura del byte-code Python, ma sembra che la lista interna ('[4,5,6]') verrà costruita 3 volte (una volta per ogni 'a') a causa del' JUMP_ABSOLUTE 16' che ti riporta indietro prima del secondo 'SETUP_LOOP',' BUILD_LIST', ecc ... – mgilson

+0

Hai ragione. Esempio fisso e aggiornato. – Jasper

+0

Scommetto che python2.7 avrebbe lo stesso rendimento anche qui ... anche se non sono sicuro del motivo per cui non ottimizzano quel BUILD_LIST. Non riesco a pensare ad alcun modo per ottenere un riferimento a questa lista - immagino che un ciclo con una lista "costante" per iterare sia un caso abbastanza raro da essere trascurato? – mgilson

3

Questo dipende dall'implementazione e dalla versione di Python e da come vengono utilizzate le "liste di costanti". Sul Cpython2.7.10 con il vostro esempio, sembra che la risposta è che la lista nella condizione della dichiarazione if viene creato solo una volta ...

>>> def foo(): 
... for i in iterable: 
...  if i in [1, 3, 5]: 
...  print(i) 
... 
>>> import dis 
>>> dis.dis(foo) 
    2   0 SETUP_LOOP    34 (to 37) 
       3 LOAD_GLOBAL    0 (iterable) 
       6 GET_ITER    
     >> 7 FOR_ITER    26 (to 36) 
      10 STORE_FAST    0 (i) 

    3   13 LOAD_FAST    0 (i) 
      16 LOAD_CONST    4 ((1, 3, 5)) 
      19 COMPARE_OP    6 (in) 
      22 POP_JUMP_IF_FALSE  7 

    4   25 LOAD_FAST    0 (i) 
      28 PRINT_ITEM   
      29 PRINT_NEWLINE  
      30 JUMP_ABSOLUTE   7 
      33 JUMP_ABSOLUTE   7 
     >> 36 POP_BLOCK   
     >> 37 LOAD_CONST    0 (None) 
      40 RETURN_VALUE   

Avviso: 16 LOAD_CONST 4 ((1, 3, 5))

ottimizzatore spioncino di Python è trasformato la nostra lista in una tupla (grazie a python!) e la memorizza come una costante. Si noti che l'ottimizzatore di spioncino può eseguire queste trasformazioni sugli oggetti solo se sa che il programmatore non ha assolutamente alcun modo di ottenere un riferimento all'elenco (altrimenti, è possibile modificare l'elenco e modificare il significato del codice). Per quanto ne so, fanno questa ottimizzazione solo per i valori letterali list, set che sono composti interamente da costanti e sono l'RHS di un operatore in. Potrebbero esserci altri casi di cui non sono a conoscenza (dis.dis è il tuo amico per la ricerca di queste ottimizzazioni).

ho accennato sopra, ma si può fare la stessa cosa con set-letterali nelle versioni più recenti di pitone (in python3.2 +, il set viene convertito in una costante frozenset). Il vantaggio è che lo set/frozenset ha un test di appartenenza più veloce in media rispetto allo list/tuple.

Problemi correlati