2010-08-25 15 views

risposta

21

E non lo fa. La tua alternativa in questo caso è any e all.

result = reduce(operator.and_, [False] * 1000) 
result = reduce(operator.or_, [True] * 1000) 

potranno essere sostituiti da

result = all([False] * 1000) 
result = any([True] * 1000) 

che fanno corto circuito.

I risultati di temporizzazione mostrano la differenza:

In [1]: import operator 

In [2]: timeit result = reduce(operator.and_, [False] * 1000) 
10000 loops, best of 3: 113 us per loop 

In [3]: timeit result = all([False] * 1000) 
100000 loops, best of 3: 5.59 us per loop 

In [4]: timeit result = reduce(operator.or_, [True] * 1000) 
10000 loops, best of 3: 113 us per loop 

In [5]: timeit result = any([True] * 1000) 
100000 loops, best of 3: 5.49 us per loop 
+0

Hai ragione. 'any()' e 'all()' sembrano essere esattamente ciò di cui ho bisogno (e probabilmente anche più chiaro). Come hai fatto quel tempismo? –

+1

Sto usando 'ipython' e il suo comando' timeit'. Ma Python ha un modulo timeit. Quindi puoi eseguire 'python -mtimeit" result = any ([True] * 10) "' dalla riga di comando per il timing. –

5

Non solo ridurre() non corto-circuito, non può possibilmente corto-circuito su tutte le voci ridursi, perché considera solo gli articoli due a un tempo. Inoltre, non ha idea delle condizioni in cui viene utilizzata la funzione cortocircuiti. (Sarebbe un po 'bello se le funzioni potessero avere una proprietà che indica il valore a cui iniziano a corto circuito, che reduce() potrebbe quindi riconoscere e utilizzare, ma non lo fanno)

+0

Ecco perché gli utenti Lisp amano così tanto il Lisp perché tutte le funzioni sono dati, è (in linea di principio) possibile fare questo tipo di rilevamento. – Lucretiel

3

Potrebbe essere possibile (vedere fate of reduce) che un'alternativa riduce l'implementazione farà un buon lavoro.

Questa idea ha perfettamente funzionato per me per rendere le cose più trasparenti nel design.

def ipairs(seq): 
    prev = None 
    for item in seq: 
     if prev is not None: 
      yield (prev, item) 
     prev = item 

def iapply(seq, func): 
    for a, b in ipairs(seq): 
     yield func(a, b) 

def satisfy(seq, cond): 
    return all(iapply(seq, cond)) 

def is_uniform(seq): 
    return satisfy(seq, lambda a, b: a == b) 

Come vedete ridurre è rotto in iapply <-ipairs.

Si prega di notare che non è equivalente a

def ireduce(seq, func): 
    prev = None 
    for item in seq: 
     if prev is None: 
      prev = item 
     else: 
      prev = func(prev, item) 
    return prev 
2

Tenete a mente che la valutazione di corto circuito non è sempre quello che si vuole. "Fissare" ridurre a corto circuito sarebbe un errore per questo motivo. Ad esempio, di recente ho dovuto modificare il mio uso di all() per ridurre() durante l'elaborazione di un elenco di moduli in django: voglio segnalare qualsiasi problema con is_valid(), non solo il primo.

+0

potrebbe usare un argomento di parole chiave per i criteri di cortocircuito, altri builtin fanno: riduci (operator.or, mylist, key = lambda x:: x <0) – LBarret