2015-06-22 19 views
8

Come si dispone di un'istruzione a più righe in una lista di comprensione o valutazione?Python 2 list comprehension e eval

stavo cercando di trasformare questo codice:

def f(x, y, b=''): 
    for i in x: 
     if i in y: 
      y.remove(i) 
      i *= 2 
     b += i 
    return b 

in una funzione lambda in questo modo:

j=lambda x,y:''.join(eval('y.remove(i);i*2')if i in y else i for i in x) 

In entrambi x è una stringa come 'onomatopoeia' e y è una lista come ['o','a','o'] .

Ma per qualche motivo, restituisce un errore di sintassi. Qualcuno può spiegarlo?

+0

quali sono i valori di 'x' e' y'? –

+0

Credo che lambda siano intenzionalmente limitati alla singola riga per migliorare la leggibilità e la leggibilità. Potresti provare a convertire quella funzione in lambda, ma è un po 'contro-pitonica. – J0HN

+0

'eval' richiede un'espressione, mentre' y.remove (i); i * 2' è un'istruzione. 'eval ('1; 1')' produce anche un 'SyntaxError'. – nymk

risposta

3

In primo luogo, probabilmente non si dovrebbe riscrivere questo con un lambda a causa degli effetti collaterali nel ciclo. Se lo vuoi davvero, non usare una valutazione.

Io suggerirei:

j = lambda x, y: ''.join((y.remove(i) or 2 * i) if i in y else i for i in x) 

Poiché il risultato di rimozione è None il secondo argomento di or sarà il risultato. Questo evita la valutazione. Ma è ancora peggio di un ciclo for.


Come notato nei commenti sulla domanda iniziale, 2 * y.pop(y.index(i)) è più leggibile rispetto al or costrutto. Farai un doppio loop su , ma le prestazioni non sembrano il problema.

2

Preferisco di gran lunga la tua funzione, ma questo farà ciò che desideri.

from itertools import chain 
j = lambda x, y: ''.join(filter(None,chain.from_iterable((i * 2,y.remove(i)) if i in y else i for i in x))) 

print(j("'onomatopoeia'",['o','a','o'])) 
'oonoomaatopoeia' 
+1

Perché non semplicemente' '' .join (2 * y.pop (y.index (i)) se io in y else i for i in x) '? – l4mpi

+0

@ l4mpi, perché sto usando il codice proprio dell'OP, anche l'indicizzazione ha un costo quindi non molto meglio del semplice filtraggio. Non avrei usato nessuno dei due approcci, se dipendesse da me –

+0

Sono d'accordo sul fatto che nessuno dei due sia davvero la strada da percorrere, ma la variante 'pop' è molto più leggibile IMO. Dubito che la velocità sia un problema, e se si eliminasse la chiamata 'remove' sarebbe probabilmente la migliore linea d'azione (ad esempio usando un contatore e diminuendo il numero di lettere). – l4mpi

0

Se si vuole scrivere buone espressioni funzionali (utilizzando lambda s, map, reduce, filter e così via), si dovrebbe evitare effetti collaterali.

Preferisco fortemente il codice come funzione piuttosto che un lambda con effetti collaterali.

Questa è un'implementazione libera-effetto collaterale nell'espressione una lambda:

>>> from functools import reduce 
>>> (lambda x, y: reduce(lambda a, b: \ 
...  (a[0]+2*b, a[1][:a[1].index(b)]+a[1][a[1].index(b)+1:]) if b in a[1] \ 
...  else (a[0]+b, a[1]), x, ('',y))[0])('onomatopoeia', ['o','a','o']) 
'oonoomaatopoeia' 

temo che non è brevebellafacile da capire * come ci si vuole che sia per un lambda. :/ (speriamo che qualcuno possa suggerire un miglioramento)

Solo un contro-esempio per scoraggiare l'uso di un lambda in questo contesto.

IMHO il problema più grande con lambdas in python è che non esiste una sintassi where come in Standard ML per definire alias variabili nella stessa espressione. Quindi, le cose diventano brutte abbastanza veloci per qualsiasi cosa non banale.


Se siete interessati a capire ciò che fa, l'idea è di utilizzare ridurre per eseguire un automi, dove il risultato (ad ogni passo) è lo "stato" del calcolo.

Lo "stato" iniziale è ('', ['o','a','o']) e la funzione di riduzione eseguirà la sostituzione secondo necessità, a partire da 'onomatopoeia'.

Questa è l'evoluzione dello "stato":

('',  ['o','a','o']) 'o' 
('oo',  ['a','o']) 'n' 
('oon',  ['a','o']) 'o' 
('oonoo',  ['a']) 'm' 
('oonoom',  ['a']) 'a' 
('oonoomaa',  []) 't' 
('oonoomaat',  []) 'o' 
('oonoomaato',  []) 'p' 
('oonoomaatop',  []) 'o' 
('oonoomaatopo', []) 'e' 
('oonoomaatopoe', []) 'i' 
('oonoomaatopoei', []) 'a' 
('oonoomaatopoeia', []) 

e prendiamo solo il primo elemento del ultimo stato.

Problemi correlati