En Python les fonctions sont des objets de premier ordre. On peut les manipuler, copier les références, les supprimer…
Exemple :
# On definit une fonction. # Jusqu'ici tout va bien... def pizza(): return "miam" print(pizza()) ## miam # On peut assigner la référence de # la fonction à une variable. delice = pizza # Et utiliser la fonction depuis la variable print(delice()) ## miam # On peut même supprimer la variable # originale. del pizza print(delice()) ## miam pizza() --------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-3-dc0f1f08233f> in <module>() ----> 1 pizza() NameError: name 'pizza' is not defined |
La fonction est un objet ordinaire qui peut donc se mettre dans une variable, mais aussi se passer en paramètre, se retourner comme valeur, etc. J’ai déjà expliqué ça dans le tuto sur les décorateurs plus en détail, mais un rappel ne fait pas de mal.
Cela veut dire que l’on peut mettre la référence d’une fonction dans une structure de données.
Par exemple dans une liste :
def pizza(): return "miam" def epinard(): return "miam aussi" def arepas(): return "decidement tout est miam" # On met les fonctions dans la liste : liste_de_fonctions = [pizza, epinard, arepas] # Et du coup on peut boucler sur les fonctions for func in liste_de_fonctions: print(func()) ## miam ## miam aussi ## decidement tout est miam # Le monde des listes s'ouvre à vous print(liste_de_fonctions[-1]()) ## decidement tout est miam f1, f2 = liste_de_fonctions[:2] print(f2()) ## miam aussi |
Mais aussi dans un dictionnaire :
dico_de_fonction = { "choix1": pizza, "choix2": epinard, "choix3": arepas } print(dico_de_fonction["choix2"]()) ## miam aussi for key, func in dico_de_fonction.items(): print("%s: %s" % (key, func())) ## choix1: miam ## choix3: decidement tout est miam ## choix2: miam aussi |
En fait, ça marche avec tout (les fonctions sont hashables) : les sets, les tuples, les deques…
On peut même faire un générateur qui yield des fonctions :
import random def fonctions_aleatoires(nombre, fonctions=liste_de_fonctions): for x in range(nombre): yield random.choice(liste_de_fonctions) for func in fonctions_aleatoires(5): print(func()) ## miam aussi ## miam ## decidement tout est miam ## miam ## miam aussi |
Python n’a certes pas les capacités de Lisp ou même Javascript pour faire de la programmation fonctionnelle, mais les fonctions restent des objets très puissants dans ce langage.
D’ailleurs, cet article est valable aussi pour les classes et les modules :)
Ça donnerait le vertige tellement il y a de possibilités!
Dans l’avant dernier exemple, s/miam1/choix1/
Merci pour ces exemples !
J’ai une question qui tue : Est-ce qu’il serait possible de stocker une fonction avec quelques arguments prédéfinis, sans avoir à redéfinir une nouvelle fonction ?
Exemple qui tue : Je veux stocker un print qui contiendrait déjà certains éléments. Quelque chose qui s’utiliserait comme ça :
...
var1 = "pouet"
var2 = "prout"
variable_qui_contient_ma_fonction_print_modifiee(var1, var2)
>>> Dès fois ça fait prout et dès fois ça fait pouet !
Est-ce que c’est possible, ou faut obligatoirement créer une nouvelle fonction ?
@A. Nonyme si je comprends bien, tu as besoin de functools.partial, exemple bien d’actualité :
Sinon pour l’anecdote à 2 francs hors sujet, je suis en train de lire Secrets of the JavaScript Ninja écrit par le créateur de jQuery et le livre revoit tous les points clés du langage avec des cas d’utilisation juste incroyables ! Notamment l’utilisation des fonctions vu dans cet article. UN MUST HAVE ;)
Pour ceux qui se demandes comment poser une lien proprement en commentaire sur un blog, le commentaire ci-dessus est un bon exemple.
@A. Nonyme: tu peux suivre l’exemple de Morgoth ou faire une lambda.
@François : merci !
@kontre + @foxmask : merci pour l’édition :)
Il y a une erreur dans le deuxième exemple.
Soit c’est :
print(pizza)
##
soit c’est :
print(pizza())
## miam
@A. Nonyme
Tu peux faire de l’expension de paramètres.
l = [
(lambda x: 2*x, [1]),
(lambda x,y: 2*x*y, [1,2]),
]
for f in l:
f[0](*f[1])
# 2
# 4
@Gontran : 1 pause café – mal à la tête tu m’as fait
Etant un joyeux utilisateur de librairies externes genre VTK j’utilisais cette possibilité depuis longtemps. Mais étant un pythonoob je ne m’en étais même pas rendu compte! Merci de m’avoir ouvert un peu plus les yeux, même si ça fait mal le matin.