2010-11-19 3 views
7

può essere scritto in una riga senza Comprensioni di lista?per-se senza comprensione di lista in una riga

for x in vec: 
    if x > 3: 
     ... 
     ... 
+10

Perché no?/Perché 1 linea? – kennytm

+0

Non ho molta familiarità con loro, ma una frase 'lambda' sarebbe appropriata qui? – Blender

+0

@blender: Un 'lambda' da solo non ha senso. Come predicato per 'i-/filter', sì. – delnan

risposta

3

No, non è possibile. I Python language reference afferma: 'clausole' 'suite' dichiarazioni

composti costituiti da uno o più Una clausola è costituito da un intestazione e un La clausola intestazioni di un particolare composto economico sono tutti allo stesso Livello di indentazione . L'intestazione di ogni proposizione inizia con una parola chiave che identifica univocamente e termina con i due punti. Una suite è un gruppo di istruzioni controllate dalla clausola . Una suite può essere una o più semplici istruzioni separate da punto e virgola sulla stessa riga dell'intestazione, seguendo i due punti dell'intestazione, oppure può essere una o più istruzioni rientrate nelle righe successive. Solo la seconda forma di suite può contenere dichiarazioni composte nidificate ; il seguente è illegale, soprattutto perché non sarebbe chiaro che se un clausola seguente else apparterrà:

if test1: if test2: print x 

Infatti, Python genera un SyntaxError per i se nidificati sopra. per quanto riguarda più formalmente for, questa è la sua grammatica in Python:

for_stmt ::= "for" target_list "in" expression_list ":" suite 
       ["else" ":" suite] 

suite   ::= stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT 

stmt_list  ::= simple_stmt (";" simple_stmt)* [";"] 

Nota che quando for è seguita da una dichiarazione senza una rientranza, questa affermazione deve essere un stmt_list, che consente solo simple_stmt casi. simple_stmt è questo:

simple_stmt ::= expression_stmt 
       | assert_stmt 
       | assignment_stmt 
       | augmented_assignment_stmt 
       | pass_stmt 
       | del_stmt 
       | print_stmt 
       | return_stmt 
       | yield_stmt 
       | raise_stmt 
       | break_stmt 
       | continue_stmt 
       | import_stmt 
       | global_stmt 
       | exec_stmt 

che non include istruzioni composte come if e for.


Detto questo, tenere presente che la sintassi di Python è finalizzata alla chiarezza. Quindi è meglio non annidare tali affermazioni, questo è ciò per cui sono stati creati i generatori/le liste. Se ritieni che il tuo calcolo sia abbastanza semplice per una singola riga, allora le comprensioni sono per te. Altrimenti, non vuoi davvero ingombrare il codice avendo tutto su una singola riga - suddividendolo bene con il rientro. Alcune linee in più non costano molto in questi giorni.

+1

Non penso che stesse chiedendo se poteva mettere quelle 2 affermazioni su una riga. Penso che voglia solo l'effetto complessivo di queste due affermazioni su una riga. – Gerrat

+0

@Eli: Dal momento che ha messo due linee di ellissi nell'esempio, sta facendo proattivamente qualcosa procedurale con 'x', rendendo la comprensione delle liste una soluzione inaccettabile. ** La comprensione delle liste non è un modo per trasformare un loop in un singolo oneliner **. – delnan

+0

@delnan: potresti avere ragione, non lo so davvero. Non è OP-intention-interpretazione un divertente gioco SO? :-) Incoraggio Roberto a chiarire cosa vuole veramente leggere –

-1

Si può immaginare quarantina in questo modo: le espressioni

def do_something(value): 
    ... 

def do_otherthing(value): 
    ... 


for x in t: do_something(x) if x>3 else do_otherthing(x) 
+0

questo è esattamente ciò che non ha chiesto: "senza comprensioni delle liste" –

+1

Per favore leggi di nuovo la domanda. –

+0

La domanda in particolare non lo richiede, in particolare perché '...' sono diverse affermazioni, nel qual caso la comprensione di una lista sarebbe non-idiomatica. – delnan

0

E 'possibile, ma list comprehension/generatori sono il tipo esatto di cosa che dovrebbe essere usato qui. A seconda di cosa vuoi fare nel tuo blocco if, potresti usare qualche forma di map o reduce, ma le comprensioni delle liste e le espressioni del generatore sono probabilmente il modo migliore per farlo.

+0

Ho bisogno di scrivere diverse righe dopo il se, in modo che non sta andando a volare – Roberto

+0

@Roberto quindi scrivere una funzione che fa quello che ti serve e usarlo nella comprensione della lista –

+0

quindi rimuovo una riga per il for/if ogni volta che devo fare qualcosa del genere, ma aggiungo una riga per dichiarare la funzione :) – Roberto

0

per x filtro (lambda I: i> 3, vec):

+0

Nota che in Python 2 questo creerà istantaneamente un nuovo elenco, invece di generare i valori pigramente. – delnan

+0

http://docs.python.org/library/itertools.html#itertools.ifilter –

3

See @KennyTM ... nessuna ragione per comprimere più di tanto.

cosa viene detto, for x in (i in vec if i > 3) fa il lavoro, così come itertools.ifilter (o semplicemente il comando incorporato filter in Python 3) con un lambda x: x > 3 predicato. Funzionano anche con tutti gli iterables e sono pigri (ad esempio, se si utilizza lo strumento break durante il ciclo, non si è controllato troppo un singolo elemento).

+0

L'intero punto, come indicato dall'OP in un commento, è che "se * x * è una parola grossa, devo digitare due volte "(momento che tira i capelli), quindi probabilmente un' filtro' + 'lambda' è la risposta appropriata per questa ... domanda. – tzot