5.3. Les fonctions natives

Il existe en Python plusieurs fonction natives spécifiquement destinées à la programmation fonctionnelle.

5.3.1. La fonction map()

La fonction map(f, iterable) applique une fonction donnée en paramètre à tous les éléments d’un itérable et revoie un nouvel itérable contenant les éléments ainsi modifiés. L’itérable original n’est pas modifié.

# on applique l'opération `x - 1` pour chaque `x` parmi les multiples de 4 entre 0 et 16
# (l'itérable renvoyé par `map()` doit être converti en liste pour être affiché)
print(list(map(lambda x: x - 1, [x * 4 for x in range(5)])))

# par améliorer la lisibilité on peut écrire l'expression sur plusieurs lignes
print(
    list(
        map(lambda x: x - 1,
            [x * 4 for x in range(5)]
            )
    )
)

for element in map(lambda x: x ** 3, range(5)):
    print(element)
[-1, 3, 7, 11, 15]
[-1, 3, 7, 11, 15]
0
1
8
27
64

On notera qu’il est relativement simple d’écrire notre propre fonction map() grâce à un générateur.

def my_map(f, iterable):
    for i in iterable:
        yield f(i)

5.3.2. La fonction filter()

La fonction filter(f, iterable) teste chaque element d’un itérable en lui appliquant une fonction f, puis renvoie une nouvelle liste composée uniquement des éléments pour lesquels f a renvoyé True.

l = [-4, 9, 54, 7, 145, 3, -8, 2390, -543]

# on ne garde que les éléments pairs
print(list(filter(lambda x: x % 2 == 0, l)))
for element in filter(lambda x: x < 0, l):    # on ne garde que les nombres négatifs
    print(element)
[-4, 54, -8, 2390]
-4
-8
-543

Comme pour la fonction map(), on peut aisément écrire notre propre fonction filter() grâce à un générateur.

def my_filter(f, iterable):
    for i in iterable:
        if f(i):
            yield i

5.3.3. La fonction reduce()

La fonction reduce(f, iterable) combine tous les éléments d’un itérable grâce à une fonction f(x, y). Une seule valeur est ensuite renvoyée par reduce(), le résultat de l’accumulation. Il est nécessaire d’importer reduce() du module functools pour pouvoir l’utiliser.

En guise d’exemple, calculons une somme et un produit en appliquant respectivement une fonction add() et une fonction anonyme aux éléments d’un itérable :

from functools import reduce


def add(x, y):
    return x + y


print(reduce(add, range(1, 10)))                # somme avec fonction nommée
print(reduce(lambda x, y: x * y, range(1, 5)))  # produit avec fonction anonyme
45
24

Pour bien comprendre le fonctionnement de reduce(), on pourrait illustrer l’exemple du produit qui calcule (((1*2)*3)*4) comme dans la figure 5.1 ci-dessous.

Fonction de réduction

Fig. 5.1 Fonction de réduction.

On peut également écrire notre propre fonction reduce() grâce à un générateur.

def my_reduce(f, iterable):
    it = iter(iterable)
    accumulator = next(it)
    for element in it:
        accumulator = f(accumulator, element)
    return accumulator

La fonction reduce() est un outil puissant avec de nombreuses applications, parfois complexes. Python propose également quelques fonctions intégrées qui agissent déjà comme des réducteurs pour les cas simples.

Fonction de réduction intégrées

Fonction

Description

Équivalence

sum(iterable)

calcule la somme de toutes les valeurs de l’itérable

reduce(lambda x, y: x + y, iterable)

all(iterable)

renvoie vrai si toutes les valeurs de l’itérable sont vraies

reduce(lambda x, y: x and y, iterable)

any(iterable)

renvoie vrai si au moins l’une des valeurs de l’itérable est vraie

reduce(lambda x, y: x or y, iterable)

min(iterable)

renvoie la valeur minimale de l’itérable

reduce(lambda x, y: x if x < y else y, iterable)

max(iterable)

renvoie la valeur maximale de l’itérable

reduce(lambda x, y: x if x > y else y, iterable)

5.3.4. Combiner les fonctions

La programmation fonctionnelle prend tout son sens lorsque nous commençons à combiner, ou imbriquer, de nombreuses fonctions simples pour obtenir un résultat complexe. Voyons par exemple comment obtenir la somme des carrés de tous les nombres impairs de 0 à 99.

print(sum(map(lambda x: x ** 2, filter(lambda x: x % 2 == 1, range(100)))))
166650

Une seule ligne de code suffit ! De plus, bien qu’un peu impressionnante au premier abord, elle se lit assez facilement : « affiche la somme des carrés des nombres entiers impairs de l’ensemble [0;100[ ».

À titre de comparaison, voici le même code en version procédurale.

sum = 0
for x in range(100):
    if x % 2 == 1:
        sum += x ** 2
print(sum)