2009-03-15 7 views
10

vedo questo genere di cose a volte:Usa caso per nested/multiple list comprehensions o espressioni generatrici. Quando è più elegante?

(k for k in (j for j in (i for i in xrange(10)))) 

Ora, questa piega davvero il mio cervello, e avrei preferito che non è stato presentato in questo modo.

Esistono casi di utilizzo o esempi di utilizzo di queste espressioni nidificate in cui era più elegante e più leggibile che se fosse stato un ciclo annidato?

Modifica: Grazie per gli esempi di modi per semplificare questo. In realtà non è quello che ho chiesto, mi chiedevo se ci fossero delle volte in cui era elegante.

+1

"A volte"? Veramente? Cosa stai leggendo? –

+1

Frammenti di codice, progetti open source. Ciò avrebbe ottenuto una revisione del codice da qualsiasi cosa avessi mai gestito. –

+0

Dove hai visto una cosa del genere? Puoi fornire un URL specifico? –

risposta

18

Controllare PEP 202 in cui era stata introdotta la sintassi di comprensione delle liste nella lingua.

per comprendere il vostro esempio, v'è una regola semplice da Guido stesso:

  • La forma [... x per ... per ... y] nidi, con l'ultimo indice variando più veloce , proprio come annidato per loops.

anche dal PEP 202, che serve per rispondere alla tua domanda:

 
Rationale 
    List comprehensions provide a more concise way to create lists in 
    situations where map() and filter() and/or nested loops would 
    currently be used. 

Se si ha una situazione del genere, si potrebbe trovare ad essere più elegante. IMHO, tuttavia, più nidificazioni di elenchi annidati potrebbero essere meno chiari nel codice di quelli annidati per cicli, dal momento che i loop di for sono facilmente analizzabili visivamente.

4

Poiché si tratta di espressioni generatrici, è possibile associare ciascuna al proprio nome per renderlo più leggibile senza alcun cambiamento nelle prestazioni. Cambiarlo in un ciclo annidato sarebbe probabilmente dannoso per le prestazioni.

irange = (i for i in xrange(10)) 
jrange = (j for j in irange) 
krange = (k for k in jrange) 

Non importa quale scegli, penso che l'esempio di più righe sia più leggibile, in generale.

5

Nel caso del tuo esempio, probabilmente scrivere come:

foos = (i for i in xrange(10)) 
bars = (j for j in foos) 
bazs = (k for k in bars) 

dati nomi più descrittivi, credo che questo sarebbe probabilmente abbastanza chiaro, e non riesco a immaginare che sia le prestazioni misurabili differenza.

Forse stai pensando di più di espressioni come:

(x for x in xs for xs in ys for ys in lst) 

- in realtà, non è nemmeno valida. Bisogna mettere le cose in un altro modo:

(x for ys in lst for xs in ys for x in xs) 

potrei scrivere che come un modo rapido di appiattimento una lista, ma in generale penso che tu sei di scrittura: il tempo si salva digitando meno di solito è equilibrata dal tempo in più che passi a ricevere l'espressione del generatore giusta.

12

Se siete preoccupati per troppa complessità su una linea, si potrebbe dividerlo:

(k for k in 
    (j for j in 
     (i for i in xrange(10)))) 

continuazione di una riga che ho sempre trovato a guardare un po 'strano in Python, ma questo renderà più facile per vedere ciò che ognuno sta passando. Dal momento che un extra di assegnazione/ricerca non è andare a fare o rompere nulla, si potrebbe anche scrivere in questo modo:

gen1 = (i for i in xrange(10)) 
gen2 = (j for j in gen1) 
gen3 = (k for k in gen2) 

In pratica, io non credo di aver mai nidificato una comprensione più profonda di 2- ea quel punto era ancora abbastanza facile da capire.

+0

Ho rimosso le fughe. – Soviut

0

L'espressione:

(k for k in (j for j in (i for i in xrange(10)))) 

è equivalente a:

(i for i in xrange(10)) 

che è quasi la stessa:

xrange(10) 

L'ultima variante è più elegante rispetto al primo.

0

Trovo può essere utile ed elegante in situazioni come queste in cui si dispone di codice in questo modo:

output = [] 
for item in list: 
    if item >= 1: 
     new = item += 1 
     output.append(new) 

si può fare una battuta del genere:

output = [item += 1 for item in list if item >= 1] 
1

Caveat: l'eleganza è in parte una questione di gusti.

La comprensione delle liste non è mai più chiaro rispetto al ciclo espanso corrispondente. Per i loop sono anche più potenti rispetto alle list comprehensions. Allora perché usarli a tutti?

Che tipo di elenco è conciso - consentono di fare qualcosa su una sola riga.

Il tempo di utilizzare una comprensione di lista è quando hai bisogno di un determinato elenco, può essere creato al volo abbastanza facilmente, e non vuoi o hai bisogno di oggetti intermedi in giro. Questo potrebbe accadere quando si ha bisogno di confezionare alcuni oggetti nel campo di applicazione di corrente in un unico oggetto che è possibile alimentare in una funzione, come di seguito:

list1 = ['foo', 'bar'] 
list2 = ['-ness', '-ity'] 
return filterRealWords([str1+str2 for str1 in list1 for str2 in list2]) 

Questo codice è quanto di più leggibile rispetto alla versione ampliata, ma è molto più breve. Evita la creazione/denominazione di un oggetto che viene utilizzato una sola volta nell'ambito corrente, che è probabilmente più elegante.

Problemi correlati