2014-12-17 2 views
6

Nella documentazione di defaultdict c'è questo esempio:In che modo Python itertools `constant_factory` esempio superior a` lambda: x`?

>>> def constant_factory(value): 
...  return itertools.repeat(value).next 

come "Un modo più veloce e più flessibile per creare funzioni costanti".

Come è superiore a

def constant_factory(value): 
    return lambda : value 

?

Si noti che, naturalmente, nessuno definirebbe una funzione per questo ... è sufficiente usare (lambda: 42) per digitare anziché chiamare constant_factory(42).

Per la creazione di una costante fabbrica di restituire un mutabile se ciò è voluto si potrebbe usare (lambda x=[]:x) (btw questo è quello che farebbe constant_factory([]), ma è qualcosa che spesso si morde indietro ... vedi ad esempio this question).

+0

Forse l'implementazione di itertools è ottimizzata e più veloce di un lambda generale? –

risposta

4

Sorprendentemente sufficiente usando itertools.repeat(value).next è in realtà circa 30% due tre volte più veloce sia Python 2 e Python 3 (con l'ovvia variante di __next__).

Non è molto ma anche non c'è motivo di sprecarlo.

PS: Direi che questo dimostra che lambda potrebbe essere migliorata (non vedo alcuna ragione logica per avere un metodo vincolato più veloce di una chiusura), ma lambda non è realmente amato nella comunità Python.

La ragione di ciò è che le primitive itertools sono implementate in C mentre un lambda esegue il bytecode Python. Il semplice ritorno di un valore catturato è molto veloce, ma è comunque un bytecode e richiede un sacco di setup/teardown come qualsiasi chiamata di funzione Python.

+1

Non è che 'lambda' sia più lento di' itertools.repeat', è che le funzioni Python sono più lente delle funzioni C. Se controlli il bytecode e i tipi di funzioni, vedrai che 'lambda' è esattamente equivalente a' def (): valore restituito'. Il fatto che 'value' sia una variabile di chiusura può anche entrare in gioco, ma un' lamda: 42' hard-coded richiede già 1.77x finchè 'repeat' nelle mie misure. – delnan