2013-12-10 13 views
12

Q1 - È il seguente un set() di un generator expression o un set comprehension? (O sono stesso Se è così, sono list & dict comprensioni anche corrispondente tipo pressofuso su generatori??)Come funzionano Python Set Comprehensions?

my_set = {x for x in range(10)} 

Q2 - La valutazione tiene considerano i valori duplicati & poi rimuoverli applicando set()?

dup_set = {x for x in [0, 1, 2, 0, 1, 2]} 

Condivide la comprensione eseguire (velocità-saggio) meglio di regolari for loop?

Aggiornamento - Ho provato a utilizzare timeit per i confronti di velocità. Non sono sicuro che io sia solo (discreto) a riguardo.

C:\>python -m timeit "s = set()" "for x in range(10):" " 
    s.add(x)" 
100000 loops, best of 3: 2.3 usec per loop 

C:\>python -m timeit "s = {x for x in range(10)}" 
1000000 loops, best of 3: 1.68 usec per loop 

Ora, utilizzando alcuni condizionali

C:\>python -m timeit "s = set()" "for x in range(10):" " 
    if x%2: s.add(x)" 
100000 loops, best of 3: 2.27 usec per loop 

C:\>python -m timeit "s = {x for x in range(10) if x%2}" 
1000000 loops, best of 3: 1.83 usec per loop 

Quindi, c'è un po 'di differenza, è dovuto alla funzionalità essere hardcoded in c?

+1

Forse potresti usare timeit (http://docs.python.org/2/library/timeit.html) o creare una funzione di temporizzazione del codice con il modulo del tempo per scoprire le differenze di tempo/velocità – Totem

risposta

7

Q1: Sì, sì, sì e sì. O almeno si comportano così. È un po 'diverso se dai un'occhiata al bytecode. Facciamo SMONTAGGIO questo codice (Python 2.7):

def list_comp(l): 
    return [x+1 for x in l] 

def dict_comp(l): 
    return {x+1:0 for x in l} 

def set_comp(l): 
    return {x+1 for x in l} 

def generator(l): 
    return (x+1 for x in l) 

Questo è quello che si ottiene:

Disassembly of list_comp: 
    2   0 BUILD_LIST    0 
       3 LOAD_FAST    0 (l) 
       6 GET_ITER    
     >> 7 FOR_ITER    16 (to 26) 
      10 STORE_FAST    1 (x) 
      13 LOAD_FAST    1 (x) 
      16 LOAD_CONST    1 (1) 
      19 BINARY_ADD   
      20 LIST_APPEND    2 
      23 JUMP_ABSOLUTE   7 
     >> 26 RETURN_VALUE 
Disassembly of dict_comp: 
    5   0 LOAD_CONST    1 (<code object <dictcomp> at 029DEE30) 
       3 MAKE_FUNCTION   0 
       6 LOAD_FAST    0 (l) 
       9 GET_ITER    
      10 CALL_FUNCTION   1 
      13 RETURN_VALUE 
Disassembly of set_comp: 
    8   0 LOAD_CONST    1 (<code object <setcomp> at 029DECC8) 
       3 MAKE_FUNCTION   0 
       6 LOAD_FAST    0 (l) 
       9 GET_ITER    
      10 CALL_FUNCTION   1 
      13 RETURN_VALUE 
Disassembly of generator: 
11   0 LOAD_CONST    1 (<code object <genexpr> at 02A8FD58) 
       3 MAKE_FUNCTION   0 
       6 LOAD_FAST    0 (l) 
       9 GET_ITER    
      10 CALL_FUNCTION   1 
      13 RETURN_VALUE      

Il bytecode è a malapena lo stesso per il comprenhension dict, il set di comprensione e il generatore. Caricano tutti un oggetto codice (<dictcomp>, <setcomp> o <genexpr>) e quindi ne fanno una funzione chiamabile. La comprensione delle liste è diversa perché genera il bytecode corrispondente alla comprensione della lista. Questa volta è interpretato e quindi non nativo.

Q2: In realtà non considera i valori duplicati poiché crea una comprensione con l'elenco che hai fornito. E poi crea l'insieme con la comprensione.

Informazioni sui tempi: La lista/Dict/Set di comprensione tende ad essere più veloce di qualsiasi altra cosa. Anche se interpretati, il bytecode generato è ottimizzato per la maggior parte dei casi con istruzioni speciali per bytecode come SET_ADD, LIST_APPEND o MAP_ADD.

+0

scritte in 'C '?? –

+0

Non sono sicuro, lo controllerò. – Vincent

+3

ovviamente ciò che è scritto dipenderà dal python che stai usando (CPython, IronPython, Jython, PyPy, ecc.). tuttavia, il punto importante è che è _native_ cioè non interpretato. –