Vous êtes déjà familier avec l'utilisation des list
comprehensions pour le filtrage de listes. Il y
a une autre manière de faire la même chose que certaines personnes
trouvent plus expressive.
Python a une fonction
filter prédéfinie qui prend deux arguments, une
fonction et une liste et retourne une liste.[8] La fonction passée comme premier argument à
filter doit elle-même prendre un argument et la
liste que filter retournera contiendra tous les
éléments de la liste passée en argument pour lesquels la fonction passée
à filter retourne vrai.
Vous avez tout compris ? Ce n'est pas aussi difficile que ça en à
l'air.
Exemple 16.7. Présentation de filter
>>> def odd(n):... return n % 2... >>> li = [1, 2, 3, 5, 9, 10, 256, -3]>>> filter(odd, li)[1, 3, 5, 9, -3]>>> [e for e in li if odd(e)]>>> filteredList = []>>> for n in li:... if odd(n):... filteredList.append(n)... >>> filteredList[1, 3, 5, 9, -3]
odd utilise la fonction prédéfinie de
modulo «%» pour retourner
True si n est impair et
False si n est
pair.
filter prend deux arguments, une
fonction (odd) et une liste
(li). odd est appelé avec
chaque élément, au fur et à mesure que la liste est parcourue. Si
odd retourne une valeur vraie (rappelez-vous
qu'en Python, toute valeur différente
de zéro est vraie), l'élément est inclut dans la liste retournée,
sinon il est filtré. Le résultat est une liste comprenant
uniquement les nombres impairs de la liste originelle, dans le
même ordre qu'ils apparaissaient en entrée.
Vous pouvez accomplir la même chose en utilisant les
list comprehensions, comme vous
l'avez vu à la Section 4.5, «Filtrage de listes».
Vous pourriez aussi accomplir la même tâche avec une boucle
for. Selon vos habitudes de programmation, cela
peut vous sembler plus «logique», mais les fonctions
comme filter sont bien plus expressives. Non
seulement elles sont plus simples à écrire, elles sont aussi plus
simple à lire. Lire la boucle for est comme
regarder un tableau de trop près, on voit tous les détails, mais
il faut quelques secondes pour comprendre l'ensemble : «Oh,
c'est juste un filtrage de liste !»
Comme vous l'avez vu à la Section 16.2, «Trouver le chemin», path peut
contenir le chemin complet ou partiel du répertoire du script en
cours d'exécution, ou une chaîne vide si le script est exécuté
depuis le répertoire en cours. De toute manière,
files contiendra les noms des fichiers qui sont
dans le même répertoire que le script en cours d'exécution.
Ceci est une expression régulière compilée. Comme vous
l'avez vu à la Section 15.3, «Refactorisation», si vous devez
utiliser la même expression régulière de manière répétée, il vaut
mieux la compiler pour obtenir de meilleures performances. L'objet
compilé a une méthode search qui prend un
seul argument, la chaîne à rechercher. Si l'expression régulière
reconnaît la chaîne, la méthode search
retourne un objet Match contenant des
informations sur ce qu'elle a trouvé, sinon elle retourne
None, la valeur nulle de
Python.
Pour chaque élément de la liste files, la
méthode search de l'objet expression
régulière compilée test va être appelée. Si
l'expression régulière reconnaît la chaîne, la méthode retourne un
objet Match, que
Python considère comme ayant pour
valeur vrai, donc l'élément sera inclus dans la liste retournée
par filter. Si l'expression régulière ne
reconnaît pas la chaîne, la méthode search
retourne None, ce que
Python considère comme ayant pour
valeur faux et donc l'élément ne sera pas inclus.
Note historique. Les versions de Python antérieures à
la version 2.0 n'avaient pas de list
comprehensions, donc on ne pouvait pas filtrer avec des list
comprehensions; la fonction
filter était la seule possibilité. Malgré
l'introduction des list comprehensions
dans la version 2.0, certaines personnes préfèrent encore l'ancien
style avec filter (et sa fonction associée,
map, que vous verrez un peu plus loin dans ce
chapitre). Les deux techniques fonctionnent actuellement, le de l'une
ou l'autre est donc une question de style. Il est question de ne plus
supporter map et filter dans
les futures versions de Python, mais aucune
décision n'a été prise pour le moment.
Exemple 16.9. Filtrage avec des list
comprehensions
files = os.listdir(path)
test = re.compile("test\.py$", re.IGNORECASE)
files = [f for f in files if test.search(f)]
On obtient exactement le même résultat qu'avec la fonction
filter. Quelle est la manière la plus
expressive ? À vous de le dire.
Footnotes
[8] Techniquement, le deuxième argument de
filter peut être n'importe quelle séquence, y
compris les listes, les tuples et les classes se comportant comme
des séquences en définissant la méthode spéciale
__getitem__. Si possible,
filter retournera le même type de données que
vous lui avez passé, donc filtrer une liste retourne une liste, mais
filtrer un tuple retourne un tuple.