Question 1Qu'affiche ce code ?def greet():
print("Salut")
f = greet
f()
Fonctions d'ordre supérieur — traiter les fonctions comme arguments et valeurs de retour
Apprends à traiter les fonctions Python comme des valeurs pour les passer en callbacks et les retourner d'autres fonctions.
Dans l'article précédent sur yield, tu as vu des fonctions qui produisent des valeurs une à une. Cette fois, tu restes côté fonctions et tu regardes les fonctions d'ordre supérieur — le mécanisme qui te permet de traiter une fonction elle-même comme une valeur.
Trois motifs à garder en tête : l'affecter à une variable, la passer en argument (un callback), et la retourner comme valeur.
Qu'est-ce qu'une fonction d'ordre supérieur — les fonctions sont aussi des valeurs
En Python, les fonctions sont des valeurs au même titre que les entiers ou les chaînes. Tu peux les mettre dans des variables, les passer à d'autres fonctions en argument, et les retourner comme résultats.
Une fonction qui prend une fonction en argument ou qui retourne une fonction comme résultat s'appelle une fonction d'ordre supérieur. Contrairement à print() ou len() qui se contentent de manipuler des valeurs, les fonctions d'ordre supérieur assemblent des morceaux de comportement.
Affecter une fonction à une variable — les fonctions sont aussi des valeurs référencées
Quand tu définis une fonction avec def, le corps de la fonction est construit en mémoire et le nom de la fonction pointe vers cet emplacement. Affecte avec a = print, et a pointe maintenant vers le même corps de fonction, donc a("HELLO") et print("HELLO") font exactement la même chose.
L'astuce, c'est de ne pas mettre les () après le nom de la fonction. Ajoute () et tu appelles la fonction à la place, et c'est la valeur de retour qui est affectée.
a = print # pas de () — affecte le corps de fonction lui-même à a
a("HELLO") # HELLO ← pareil que print("HELLO")
print(id(print)) # par ex. 4395020128
print(id(a)) # la même adresse apparaît
# Tes propres fonctions marchent pareil
def greet():
print("Bonjour")
say = greet # construit un alias say
say() # Bonjour
Avec ou sans () change le sens
a = print est la forme qui passe la fonction, alors que a = print("HELLO") est la forme qui appelle la fonction et passe le résultat. Dans le second cas, la valeur de retour de print("HELLO") (None) atterrit dans a, donc appeler a() lève TypeError: 'NoneType' object is not callable.
Passer une fonction en argument — les callbacks
L'usage le plus typique des fonctions d'ordre supérieur est le callback — « une fonction passée à une autre fonction et appelée à un moment précis », où « c'est l'appelant qui décide du comportement réel ».
Par exemple, imagine une routine qui « affiche une salutation pour une liste de trois noms », mais tu veux n'échanger que le style de salutation depuis le site d'appel. Garde le corps comme une boucle qui prend les noms un par un, et prends la partie formatage en argument fonction — alors l'appelant peut réutiliser la routine en changeant simplement le modèle de salutation.
def greet_all(names, formatter):
for name in names:
print(formatter(name))
def formal(name):
return f"Bonjour {name}, merci pour votre fidélité."
def casual(name):
return f"Salut, {name} !"
greet_all(["Alice", "Léa", "Hugo"], formal)
# Bonjour Alice, merci pour votre fidélité.
# Bonjour Léa, merci pour votre fidélité.
# Bonjour Hugo, merci pour votre fidélité.
greet_all(["Alice", "Léa", "Hugo"], casual)
# Salut, Alice !
# Salut, Léa !
# Salut, Hugo !
greet_all n'est qu'une boucle ; comment transformer chaque nom en ligne de salutation est laissé à l'argument formatter.Brancher avec des callbacks dédiés à chaque cas
Tu n'es pas limité à passer un seul callback. « Utilise cette fonction en cas de succès, celle-là en cas d'échec » est aussi un usage naturel — partout où tu voudrais choisir entre plusieurs callbacks.
Par exemple, quand tu veux changer de comportement selon qu'un nombre est pair ou impair, la fonction qui décide peut ne faire qu'un branchement if, et laisser le traitement réel à deux fonctions fournies par l'appelant.
def process_number(number, even_callback, odd_callback):
if number % 2 == 0:
even_callback(number)
else:
odd_callback(number)
def handle_even(n):
print(f"{n} est pair")
def handle_odd(n):
print(f"{n} est impair")
process_number(4, handle_even, handle_odd) # 4 est pair
process_number(7, handle_even, handle_odd) # 7 est impair
Retourner une fonction comme valeur — les clôtures en pratique
L'autre motif d'ordre supérieur, c'est « retourner une fonction comme valeur ». Retourner une fonction interne avec return a été couvert dans l'article sur les clôtures ; ici, l'angle pratique, c'est « remettre à l'appelant une fonction qui se souvient déjà de son réglage ».
Par exemple, quand tu veux produire en série des fonctions de log qui apposent le même préfixe à chaque appel, monte make_logger("INFO") pour le logger INFO et make_logger("ERROR") pour le logger ERROR — et le code appelant reste aussi court qu'info("Processus démarré").
def make_logger(prefix):
def log(message):
print(f"[{prefix}] {message}")
return log # retourne la fonction elle-même
info = make_logger("INFO")
error = make_logger("ERROR")
info("Processus démarré") # [INFO] Processus démarré
error("Connexion échouée") # [ERROR] Connexion échouée
info("Processus terminé") # [INFO] Processus terminé
- info = make_logger("INFO") — reçoit une fonction qui se souvient de INFO
- error = make_logger("ERROR") — reçoit une fonction distincte qui se souvient de ERROR
- Contient
prefix = "INFO" returnlelogdéfini à l'intérieur
- Affiche
[INFO] ...à chaque appel
- Contient
prefix = "ERROR" returnune fonctionlogdistincte
- Un objet fonction distinct, indépendant d'
info
Vérification des connaissances
Répondez à chaque question une par une.
Question 2Quelle ligne passe say_hi comme callback ?
Question 3Qu'affiche info("OK") après que ce code s'est exécuté ?def make_logger(prefix):
def log(message):
print(f"[{prefix}] {message}")
return log
info = make_logger("INFO")