2010-03-24 14 views
12

Ho una lista, diciamo, a = [[1,2],[3,4],[5,6]]Aggiunta voce alle liste all'interno di una lista di comprensione

voglio aggiungere la stringa 'a' ad ogni elemento della lista a.

quando uso:

a = [x.append('a') for x in a] 

esso restituisce [None,None,None].

Ma se uso:

a1 = [x.append('a') for x in a] 

allora fa qualcosa di strano.

a, ma non a1 è [[1,2,'a'],[3,4,'a'],[5,6,'a']].

Non capisco perché la prima chiamata restituisca [None, None, None] né perché le seconde modifiche su a anziché a1.

risposta

7

Per il primo caso, il motivo per cui restituisce [None, None, None] è perché la funzione list.append restituisce None e questo è ciò che memorizza nell'elenco.

Nel secondo caso, è perché l'elenco è modificabile e ogni volta che si aggiunge il valore, l'elenco originale viene modificato.

Ciò di cui si ha bisogno è un operatore di accodamento non sul posto, ad esempio +. Ad esempio [x + ['a'] for x in a].

23

list.append muta la lista stessa e restituisce None. La comprensione delle liste serve per memorizzare il risultato, che in questo caso non è quello che vuoi se vuoi semplicemente modificare gli elenchi originali.

>>> x = [[1, 2], [3, 4], [5, 6]] 
>>> for sublist in x: 
...  sublist.append('a') 
... 
>>> x 
[[1, 2, 'a'], [3, 4, 'a'], [5, 6, 'a']] 
3

(Questa è una combinazione delle risposte di Mike Graham e Sykora):

Se si desidera semplicemente modificare i valori in-place, provare un regolare per-loop, e non una lista di comprensione :

for sublist in a: 
    sublist.append('a') 

Se si desidera lasciare un solo, e mettere il risultato in A1:

a1 = [sublist + ['a'] for sublist in a] 

Mentre spiegato, append modifica l'elenco, ma restituisce Nessuno, mentre + lascia l'elenco da solo, ma restituisce un nuovo elenco aggiunto.

+3

Che dovrebbe essere a1 = [sottolista + ['a'] per sottolista in a]. Appuntare le parentesi attorno a 'a'. –

+0

Whoops. Fisso. Grazie. – Oddthinking

0

lasciare il a = e utilizzare l'effetto collaterale sulla a:

[x.append('a') for x in a] 
print a 
+2

Per favore, no. Buttare via una comprensione delle liste solo per utilizzare i suoi effetti collaterali è una cattiva forma; il tuo suggerimento funziona, ma è malvisto proprio come l'uso simile di 'map' è stato disapprovato. L'esplicito è migliore di implicito; usa un ciclo piuttosto che una lista di comprensione. – tzot

6

Come altri hanno detto, append muta la lista stessa e non è necessario assegnare a una variabile. Eseguirlo cambia i suoi dati, aggiornando in modo efficace tutti quelli che lo indicano.

Ma, c'è un trucco che uso quando voglio fare cose in modo funzionale * mentre mutando oggetti esistenti (piuttosto che costruire quelli nuovi, in questo caso utilizzando a=[x + ['a'] for x in a], o specificamente il x + ['a']).

Quindi, se siete abbastanza coraggiosi si può anche fare questo:

>>> a=[[1,2],[3,4],[5,6]] 
>>> a=[x.append('a') or x for x in a] 
>>> a 
[[1, 2, 'a'], [3, 4, 'a'], [5, 6, 'a']] 

Questo funziona perché append rendimenti None, e il or continua a cercare un valore di verità-y, che xè (è un list con almeno quello che è stato aggiunto ad esso).

Perché ho bisogno anche di questo?

Diciamo che avete una lista e si desidera inserire alcuni dei suoi membri ad una nuova lista, e aggiornare i riferimenti di conseguenza:

Così si ha la lista all:

>>> all = [[], [], [], []] 

Alcuni di è inserito e aggiornato per un nuovo elenco x:

>>> x = [i.append('x') or i for i in all[:2]] 
>>> x 
[['x'], ['x']] 

Alcuni di all è anche inserito e u pdated a un elenco y:

>>> y = [i.append('y') or i for i in all[1:3]] 

all è aggiornato:

>>> all 
[['x'], ['x', 'y'], ['y'], []] 

Ma x è anche aggiornato:

>>> x 
[['x'], ['x', 'y']] 

E y è generato come previsto:

>>> y 
[['x', 'y'], ['y']] 

Nel complesso, per compiti semplici, consiglierei di utilizzare un ciclo for aggiornando esplicitamente. Questo è ciò che è considerato pitonico.

Tecnicamente parlando, se si ha l'accesso alla classe lista, si potrebbe fare questo una funzione:

def more_functional_append(self, x): 
    self.append(x) 
    return self 
  • functional programming si basa su ogni affermazione facendo essenzialmente una cosa, e non avere effetti collaterali (in modo , non mutando e ritornando). append non è molto funzionale poiché muta una lista (la pura programmazione funzionale ha solo oggetti immutabili) e non restituisce un risultato da passare ad altre azioni (funzioni). Utilizzando concetti di programmazione funzionale è possibile creare grandi one-liner di grandi dimensioni che nessuno può leggere, noto anche come "sicurezza del lavoro" o "codice errato".
+0

Ho una vista diversa su questa risposta ora, quindi se stai leggendo questo per favore commenta così posso aggiornarlo. C'è una caratteristica fondamentale mancante per la programmazione funzionale qui che è immutabile e dovrei espandermi su questo. –

1

È possibile utilizzare l'elenco Inoltre all'interno di un elenco di comprensione, in questo modo:

a = [x + [ 'a'] per x in una]

Questo dà la desiderata risultato per a. Uno potrebbe renderlo più efficiente in questo caso assegnando ['a'] a un nome di variabile prima del ciclo, ma dipende da ciò che si vuole fare.

0

Nella prima assegnazione di valore della comprensione della lista un errore di attributo, l'oggetto 'NoneType' non ha attributo 'append', aiuta a spiegare perché la tua lista, a, sarà caricata con None (s). Per far sì che la mia console lanci l'errore, ho usato x come variabile per la comprensione delle liste e anche come iteratore.

Traceback (most recent call last): 
x = [x.append('a') for x in a] 
AttributeError: 'NoneType' object has no attribute 'append' 

Quindi, ho ripristinato un x per e ha gettato lo stesso errore.

Traceback (most recent call last): 
a = [x.append('a') for x in a] 
AttributeError: 'NoneType' object has no attribute 'append' 
Problemi correlati