3.5. Filtrare le liste

Come già si è detto, Python offre potenti strumenti per mappare delle liste in liste corrispondenti, per mezzo delle “list comprehension”. Queste possono essere combinate con un meccanismo di filtro, facendo in modo che alcuni elementi delle liste vengano mappati ed altri vengano ignorati completamente.

Esempio 3.13. Sintassi per filtrare una lista

[mapping-expression for element in source-list if filter-expression]

Questa è un'estensione della “list comprehensions” che tutti conosciamo ed amiamo. I primi due terzi sono uguali; l'ultima parte, a cominciare dalla parola chiave if, è l'espressione di filtro. Un'espressione di filtro può avere qualunque valore, purché abbia come risultato un valore vero o falso ( il che in Python comprende quasi tutto). Ogni elemento per cui l'espressione di filtro risulti vera viene inclusa nella lista risultante. Tutti gli altri elementi sono ignorati, quindi non sono mai processati dall'espressione di mappatura e non sono inclusi nella lista risultante.

Esempio 3.14. Introduzione alle liste filtrate

>>> li = ["a", "mpilgrim", "foo", "b", "c", "b", "d", "d"]
>>> [elem for elem in li if len(elem) > 1]       1
['mpilgrim', 'foo']
>>> [elem for elem in li if elem != "b"]         2
['a', 'mpilgrim', 'foo', 'c', 'd', 'd']
>>> [elem for elem in li if li.count(elem) == 1] 3
['a', 'mpilgrim', 'foo', 'c']
1 L'espressione di mappatura in questo caso è semplice (restituisce il valore di ogni elemento), perciò concentriamoci sull'espressione di filtro; Python esegue un ciclo sulla lista e ciascun elemento attraversa l'espressione di filtro. Se l'espressione di filtro è vera, l'elemento viene mappato ed il risultato dell'espressione di mappatura è incluso nella lista risultante. In questo caso si vogliono eliminare tutte le stringhe di un carattere, per ottenere solo le stringhe più lunghe.
2 Qui stiamo filtrando per eliminare uno specifico valore, b. Da notare che questo filtra tutte le occorrenze di b, dato che ogni volta che appare tale valore l'espressione di filtro risulta falsa.
3 La funzione count è un metodo che restituisce il numero di volte che un valore è presente in una lista. Si potrebbe pensare che un tale filtro elimini i duplicati da una lista, restituendo una lista che contenga solo una copia di ogni valore della lista originale. Ma non è così, perché i valori che appaiono due volte nella lista originale (in questo caso b e d)vengono esclusi completamente. Ci sono modi per eliminare i duplicati da una lista, ma filtrare la lista non è tra questi.

Esempio 3.15. Filtrare una lista in apihelper.py

    methodList = [method for method in dir(object) if callable(getattr(object, method))]

Questo appare complicato ed in effetti lo è, ma la struttura di base è la stessa. L'intera espressione di filtro restituisce una lista che viene assegnata alla variabile methodList. La prima metà dell'espressione è la componente di mappatura. L'espressione di mappatura è un'espressione di uguaglianza; restituisce il valore di ciascun elemento. L'espressione dir(object) restituisce una lista di attributi e metodi di object; questa è la lista che stiamo mappando. Quindi, l'unica parte veramente nuova è l'espressione di filtro che segue la parola chiave if.

L'espressione di filtro spaventa un po', ma solo a prima vista. Si è già detto dei metodi callable, getattr, e di in. Come si è visto nella sezione precedente, l'espressione getattr(object, method) restituisce una funzione se object è un modulo e method è il nome di una funzione del modulo.

Quindi questa espressione prende un oggetto che abbia un nome, ne estrae la lista dei nomi degli attributi, dei metodi, delle funzioni e di qualche altra cosa, quindi filtra la lista per eliminare tutto ciò che non ci interessa. La scrematura della lista viene fatta partendo dal nome di ogni attributo/funzione/metodo ed ottenendo un riferimento all'oggetto corrispondente, attraverso la funzione getattr. Quindi si controlla se l'oggetto è invocabile, come è il caso per i metodi e le funzioni, sia quelle built-in (come il metodo pop di una lista) sia quelle definite dall'utente (come la funzione buildConnectionString del modulo odbchelper). Si scartano gli altri attributi, come l'attributo __name__ che è in ogni modulo.

Ulteriori letture