Python Language Elenco delle comprensioni


Esempio

Una comprensione delle liste crea una nuova list applicando un'espressione a ciascun elemento di un iterabile . La forma più elementare è:

[ <expression> for <element> in <iterable> ]

C'è anche una condizione opzionale "se":

[ <expression> for <element> in <iterable> if <condition> ]

Ogni <element> in <iterable> è collegato a <expression> se la ( <condition> ) <condition> valutata come vera . Tutti i risultati vengono restituiti contemporaneamente nella nuova lista. Le espressioni del generatore vengono valutate pigramente, ma la comprensione delle liste valuta immediatamente l'intero iteratore - consumando memoria proporzionale alla lunghezza dell'iteratore.

Per creare un list di interi quadrati:

squares = [x * x for x in (1, 2, 3, 4)]
# squares: [1, 4, 9, 16]

L'espressione for imposta x per ciascun valore a sua volta da (1, 2, 3, 4) . Il risultato dell'espressione x * x è aggiunto ad una list interna. L' list interno viene assegnato ai squares variabili quando completato.

Oltre ad un aumento di velocità (come spiegato qui ), una comprensione di lista è approssimativamente equivalente al seguente ciclo:

squares = []
for x in (1, 2, 3, 4):
    squares.append(x * x)
# squares: [1, 4, 9, 16]

L'espressione applicata a ciascun elemento può essere complessa quanto necessaria:

# Get a list of uppercase characters from a string
[s.upper() for s in "Hello World"]
# ['H', 'E', 'L', 'L', 'O', ' ', 'W', 'O', 'R', 'L', 'D']

# Strip off any commas from the end of strings in a list
[w.strip(',') for w in ['these,', 'words,,', 'mostly', 'have,commas,']]
# ['these', 'words', 'mostly', 'have,commas']

# Organize letters in words more reasonably - in an alphabetical order
sentence = "Beautiful is better than ugly"
["".join(sorted(word, key = lambda x: x.lower())) for word in sentence.split()]
# ['aBefiltuu', 'is', 'beertt', 'ahnt', 'gluy']

altro

else può essere usato nei costrutti di comprensione delle liste, ma attenzione alla sintassi. Le clausole if / else devono essere usate prima for ciclo, non dopo:

# create a list of characters in apple, replacing non vowels with '*'
# Ex - 'apple' --> ['a', '*', '*', '*' ,'e']

[x for x in 'apple' if x in 'aeiou' else '*']
#SyntaxError: invalid syntax

# When using if/else together use them before the loop
[x if x in 'aeiou' else '*' for x in 'apple']
#['a', '*', '*', '*', 'e']

Nota: utilizza un costrutto linguistico diverso, un'espressione condizionale , che a sua volta non fa parte della sintassi di comprensione . Mentre il if dopo il for…in è una parte delle list comprehensions e viene usato per filtrare elementi dalla sorgente iterabile.


Doppia iterazione

L'ordine di doppia iterazione [... for x in ... for y in ...] è naturale o contro-intuitivo. La regola generale è quella di seguire un equivalente for ciclo:

def foo(i):
    return i, i + 0.5

for i in range(3):
    for x in foo(i):
        yield str(x)

Questo diventa:

[str(x)
    for i in range(3)
        for x in foo(i)
]

Questo può essere compresso in una riga come [str(x) for i in range(3) for x in foo(i)]


Mutazione sul posto e altri effetti collaterali

Prima di utilizzare la comprensione delle liste, comprendere la differenza tra le funzioni chiamate per i loro effetti collaterali ( mutanti o funzioni sul posto ) che in genere restituiscono None e le funzioni che restituiscono un valore interessante.

Molte funzioni (in particolare le funzioni pure ) prendono semplicemente un oggetto e restituiscono un oggetto. Una funzione sul posto modifica l'oggetto esistente, che è chiamato effetto collaterale . Altri esempi includono operazioni di input e output come la stampa.

list.sort() ordina un elenco sul posto (nel senso che modifica l'elenco originale) e restituisce il valore None . Pertanto, non funzionerà come previsto in una comprensione di lista:

[x.sort() for x in [[2, 1], [4, 3], [0, 1]]]
# [None, None, None]

Invece, sorted() restituisce una list ordinata piuttosto che ordinare sul posto:

[sorted(x) for x in [[2, 1], [4, 3], [0, 1]]]
# [[1, 2], [3, 4], [0, 1]]

È possibile utilizzare la comprensione per gli effetti collaterali, come I / O o le funzioni sul posto. Tuttavia, un ciclo for è solitamente più leggibile. Mentre questo funziona in Python 3:

[print(x) for x in (1, 2, 3)]

Usa invece:

for x in (1, 2, 3):
    print(x)

In alcune situazioni, le funzioni di effetti collaterali sono adatte per la comprensione delle liste. random.randrange() ha l'effetto collaterale di cambiare lo stato del generatore di numeri casuali, ma restituisce anche un valore interessante. Inoltre, next() può essere chiamato su un iteratore.

Il seguente generatore di valori casuali non è puro, ma ha senso quando il generatore casuale viene reimpostato ogni volta che viene valutata l'espressione:

from random import randrange
[randrange(1, 7) for _ in range(10)]
# [2, 3, 2, 1, 1, 5, 2, 4, 3, 5]

Spazio bianco nella comprensione delle liste

Comprensioni di lista più complicate possono raggiungere una lunghezza indesiderata o diventare meno leggibili. Sebbene meno comune negli esempi, è possibile rompere una comprensione di lista in più linee in questo modo:

[
    x for x
    in 'foo'
    if x not in 'bar'
]