Une fonction permet de regrouper une suite d'instruction qui seront exécutées lors de l'appel de cette dernière.
Une fonction peut exécuter un comportement différent à chaque fois grâce à l'utilisation de paramètres qui peuvent varier lors de l'appel de la fonction (grâce à l'envoi d'arguments).
Créer une fonction
Pour créer une fonction, on utilise le mot clé def :
def foo(): print("La fonction s'exécute")
Il suffit ensuite d'utiliser le nom de la fonction suivie de parenthèses pour exécuter le code qu'elle contient :
def foo(): print("La fonction s'exécute") foo()
Les paramètres
Une fonction peut posséder un ou plusieurs paramètres :
def somme(a, b): print(a + b) somme(10, 5)
Quand on appelle la fonction, on peut envoyer des objets à ces paramètres. Ces objets sont appelés arguments.
Retourner une valeur
On peut retourner une valeur dans une fonction grâce au mot clé return.
Ce mot clé a pour effet de mettre fin à l'exécution de la fonction. Dans le code suivant, le print ne sera ainsi jamais exécuté. On parle de code inaccessible :
def somme(a, b): return a + b print(a + b) somme(10, 5)
La valeur retournée par une fonction peut être récupérée dans une variable lors de l'appel de la fonction :
def somme(a, b): return a + b resultat = somme(10, 5) print(resultat)
Utiliser une variable comme argument
Afin de rendre le code encore plus dynamique, il est possible de passer une variable en argument au moment d'appeler une fonction.
def afficher(message): print(message) texte = "Hello, world!" afficher(texte)
Utiliser des valeurs par défaut pour les paramètres
Il est tout à fait possible d'attribuer une valeur par défaut aux paramètres lors de la définition de la fonction. Ainsi, la fonction peut être appelée sans fournir certains arguments.
def saluer(nom, message="Bonjour"): print(message, nom) saluer("Patrick")
Attention
Tous les paramètres qui ont une valeur par défaut doivent être placés après ceux qui n'en ont pas. Sinon, Python lèvera une erreur.
Ainsi, il n'est pas possible de faire ceci :
def saluer(nom="Patrick", message): print(message, nom)
Aussi, lors de l'appel à la fonction, vous pouvez passer un argument différent à un paramètre qui possède une valeur par défaut :
def saluer(nom, message="Bonjour"): print(message, nom) # Appel en redéfinissant le paramètre message saluer("Patrick", "Hello")
Les paramètres *args et **kwargs
Pour rendre une fonction encore plus flexible, *args et **kwargs permettent d'utiliser un nombre variable d'arguments positionnels et nommés.
def afficher_infos(*args, **kwargs): print("Args:", args) print("Kwargs:", kwargs) afficher_infos(1, 2, 3, nom="Patrick", age=30) # Args: (1, 2, 3) Kwargs: {'nom': 'Patrick', 'age': 30}
Dans la définition de ma fonction, je peux évidemment définir en premier des paramètres obligatoires. Ensuite, *args capture tous les arguments positionnels supplémentaires. Puis, vous pourriez très bien avoir des paramètres nommés, suivi de **kwargs qui récupère les arguments nommés supplémentaires.
def afficher_infos(a, b, c, *args, nom="Patrick", age=0, **kwargs): print("a:", a) print("b:", b) print("c:", c) print("nom:", nom) print("age:", age) print("Args:", args) print("Kwargs:", kwargs) afficher_infos(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, nom="Patrick", age=30, taille=180, poids=70) # a: 1 # b: 2 # c: 3 # nom: Patrick # age: 30 # Args: (4, 5, 6, 7, 8, 9, 10) # Kwargs: {'taille': 180, 'poids': 70}
Variables Globales et Locales : différences et bonnes pratiques
Ici, nous parlerons de portée des variables. En d'autres termes, où ma variable est-elle accessible dans le code ?
Variable globale
Une variable globale est déclarée en dehors d'une fonction. Elle est accessible dans tout le programme.
def f1(): print(x) x = 5 f1() # Affiche 5 print(x) # Affiche 5
Variable locale
Une variable locale est déclarée à l'intérieur d'une fonction. Elle n'est accessible qu'à l'intérieur de cette fonction. Si une variable globale porte le même nom, la variable locale va simplement masquer la variable globale.
def f1(): x = 2 print(x) x = 1 print(x) # Affiche 1 (variable globale) f1() # Affiche 2 (variable locale) print(x) # Affiche encore 1 (variable globale inchangée)
Utilisation du mot-clé global
Pour accéder et modifier une variable globale depuis une fonction, il faut utiliser le mot-clé global :
def f1(): global x print(x) # Affiche la valeur de la variable globale x x = 5 # Modifie la variable globale x x = 1 f1() # Affiche 1, puis modifie x à 5 print(x) # Affiche 5
Attention
Il est fortement déconseillé d'utiliser le mot-clé global, car cela peut rendre le code plus difficile à maintenir.
En effet, l'utilisation du mot-clé global peut rendre le comportement d'une fonction imprévisible. Il faut bien comprendre que dans ce cas, la fonction modifie une variable extérieure à son propre scope ! On risque d'avoir des effets de bord imprévisibles.
Cela va à l'encontre du principe d'encapsulation, où le but est que chaque fonction soit indépendante (et prévisible !).
Prenons cet exemple :
message = "Bonjour" def fonction_1(): global message message = "Au revoir" print("Dans fonction_1:", message) def fonction_2(): print("Dans fonction_2:", message) # Première exécution fonction_2() # Affiche: Dans fonction_2: Bonjour fonction_1() # Affiche: Dans fonction_1: Au revoir fonction_2() # Affiche: Dans fonction_2: Au revoir print("\nLe message a été modifié de l'extérieur!")
La variable message est initialisée à "Bonjour". Dès l'appel de fonction1, la variable globale est modifiée pour prendre la valeur "Au revoir". Ce qui peut être déroutant, c'est que fonction2 affichera désormais "Au revoir" au lieu de "Bonjour".
Ici, le cas est simple, mais dans un programme plus complexe, ces effets de bord peuvent rapidement compliquer la compréhension et la maintenance du code.
Fonctions imbriquées
Il est possible de définir une fonction à l'intérieur d'une autre. De cette manière, il est possible de créer une "closure" (qu'on peut traduire par "fermeture"), permettant à la fonction interne d'accéder aux variables de la fonction englobante.
def f1(debut): suite = ", Milieu de la phrase, " def f2(suite2): fin = ", Fin de la phrase" return debut + suite + suite2 + fin return f2 phrase1 = f1("Début de la phrase") print(phrase1("Début de la fin haha"))
Les fonctions sont des objets de première classe
En python, les fonctions sont considérées comme des objets de première classe.
À noter
L'expression "de première classe" (ou "first-class" en anglais) fait référence à un concept en programmation où un type de donnée (comme une fonction) peut être traité comme n'importe quel autre type de donnée.
Cela signifie que les fonctions en Python peuvent être :
-
Affectées à des variables
def carre(x): return x * x # Affectation de la fonction à une variable calculer = carre # Utilisation de la variable comme une fonction resultat = calculer(5) print(resultat) # Affiche: 25 -
Passées en argument à d'autres fonctions
def carre(x): return x * x def cube(x): return x * x * x def appliquer_fonction(f, valeur): return f(valeur) # Passage de différentes fonctions en argument resultat1 = appliquer_fonction(carre, 4) resultat2 = appliquer_fonction(cube, 4) print(resultat1) # Affiche: 16 print(resultat2) # Affiche: 64 -
Retournées par d'autres fonctions
def creer_fonction_puissance(n): def puissance(x): return x ** n return puissance # Création de fonctions spécifiques au_carre = creer_fonction_puissance(2) au_cube = creer_fonction_puissance(3) # Utilisation des fonctions retournées print(au_carre(4)) # Affiche: 16 print(au_cube(4)) # Affiche: 64