Believemy logo purple

Les fonctions en Python

Le mot-clé def permet de créer des fonctions nommées en Python.
Believemy logo

Le mot-clé def est un pilier de la programmation en Python.

Il permet de définir des fonctions nommées, c’est-à-dire des blocs de code que l’on peut réutiliser plusieurs fois dans un programme.

Utiliser des fonctions permet de :

  • Structurer son code de manière modulaire ;
  • Réutiliser des instructions sans les répéter ;
  • Améliorer sa lisibilité tout en augmentant sa maintenabilité.

Le mot-clé def est donc la porte d’entrée vers une programmation plus propre, plus efficace et plus évolutive.

 

Syntaxe de base avec def

La syntaxe de base d’une fonction en Python est très simple :

PYTHON
def nom_de_la_fonction(parametres):
    instruction(s)
    return résultat

Voici les éléments clés d'une fonction avec Python :

  • def est le mot-clé utilisé pour définir une fonction ;
  • On suit avec le nom de la fonction, puis une liste de paramètres entre parenthèses ;
  • Le bloc d’instructions est indenté (souvent 4 espaces).

Enfin, on peut retrouver le mot-clé return qui permet de renvoyer une valeur au moment de l’appel de la fonction.

En Python, l’indentation est obligatoire. C’est ce qui délimite le bloc d’instructions appartenant à la fonction. 😉

 

Exemple simple de fonction avec def

Prenons un exemple de fonction très simple :

PYTHON
def addition(x, y):
    return x + y

resultat = addition(3, 5)
print(resultat)  # Résultat : 8

Dans cet exemple :

  • def addition(x, y) crée une fonction appelée addition qui prend deux paramètres ;
  • Elle retourne la somme des deux (x + y) ;
  • On appelle notre fonction en utilisant son nom suivi des arguments que l'on souhaite lui donner avec addition(3, 5) qui renvoie 8, que l’on stocke dans une variable resultat ;
  • Enfin, print() affiche ce résultat.

Une fonction peut être appelée plusieurs fois avec des arguments différents. C’est ce qui en fait un outil puissant pour automatiser des opérations répétitives. 😋

 

Paramètres et arguments

Comme nous l'avons vu rapidement dans notre exemple précédent, les fonctions définies avec def peuvent recevoir des paramètres, c’est-à-dire des valeurs d’entrée qui influencent leur comportement.

Les types de paramètres en Python

Les paramètres positionnels

Ils sont passés dans l’ordre défini :

PYTHON
def saluer(prenom, nom):
    return f"Bonjour {prenom} {nom}"

print(saluer("Alice", "Durand")) # Bonjour Alice Durant

Comme on peut le voir, la première valeur donnée "Alice" sera automatiquement attribuée sur la variable prenom de notre fonction. Idem pour "Durand" qui ira dans l'argument en seconde position.

Ceci veut dire que si l'on inverse "Alice" et "Durant", le prénom et le nom de notre utilisateur sera ... inversé ! 😬

PYTHON
def saluer(prenom, nom):
    return f"Bonjour {prenom} {nom}"

print(saluer("Durant", "Alice")) # Bonjour Durant Alice

Ici "Durant" va bien dans la variable prenom, alors que "Alice" va dans la variable nom. C'est ce qu'on appelle des paramètres positionnels.

 

Les arguments nommés

Au contraire des paramètres positionnels, ils permettent de spécifier la valeur d’un paramètre, quel que soit l’ordre :

PYTHON
def saluer(prenom, nom):
    return f"Bonjour {prenom} {nom}"

print(saluer(nom="Durant", prénom="Alice"))
# Bonjour Alice Durant

Ici, nous n'aurons plus aucun problème d'inversement !

 

Les valeurs par défaut

Enfin on peut attribuer une valeur par défaut à un paramètre :

PYTHON
def saluer(prenom, nom="Dupont"):
    return f"Bonjour {prenom} {nom}"

print(saluer("Julie"))  # Bonjour Julie Dupont

Les paramètres avec valeurs par défaut doivent toujours être placés après les paramètres obligatoires.

 

Retourner une valeur avec return

Le mot-clé return permet à une fonction de renvoyer une valeur. C’est ce qui différencie une fonction qui "renvoie" d’une fonction qui "fait" quelque chose.

On l'utilise généralement pour :

  • Obtenir un résultat calculé par la fonction ;
  • Chaîner plusieurs fonctions entre-elles ;
  • Séparer traitement et affichage.

Prenons un petit exemple :

PYTHON
def carre(x):
    return x ** 2

résultat = carre(4)
print(résultat)  # 16

Une fonction peut contenir plusieurs return, ce qui permet de retourner différents résultats selon les conditions.

PYTHON
def evaluation(note):
    if note >= 10:
        return "Réussi"
    else:
        return "Échoué"

 

Les fonctions qui ne retournent jamais rien

Contrairement à ce que nous venons de voir, toutes les fonctions ne retournent pas une valeur explicite.

Parfois, une fonction modifie un objet existant ou effectue une action externe (affichage, écriture fichier, etc.).

Prenons un autre exemple pour illustrer tout ça :

PYTHON
def dire_bonjour(nom):
    print(f"Bonjour {nom}")

Cette fonction affiche directement une chaîne de caractères, sans jamais retourner quelque chose !

 

Les annotations de type sur les fonctions

Python permet d’ajouter des annotations de types aux paramètres et au retour d’une fonction. Cela ne change pas le comportement de la fonction, mais facilite la lecture du code et permet aux éditeurs ou outils de linters d’analyser les types attendus.

Voici un exemple :

PYTHON
def saluer(prenom: str, age: int) -> str:
    return f"Bonjour {prenom}, vous avez {age} ans."

Les annotations de type indiquent :

  • que prenom est une chaîne de caractères ;
  • qu'age est un entier ;
  • que cette fonction retourne une chaîne.

Attention, ces annotations ne sont pas obligatoires et ne sont pas exécutées. Python ne vérifie pas les types à l’exécution. Elles ressemblent beaucoup à ce qu'on peut trouver avec TypeScript.

Le typage permet d'améliorer la documentation du code, de mieux travailler en équipe tout en évitant des erreurs avec des outils comme MyPy.

 

Docstrings et documentation

Il est courant de voir des docstrings quand on parle des fonctions ! 😉

Une docstring (pour documentation string 🇺🇸) est un commentaire placé juste après la définition d’une fonction, destiné à décrire ce que fait cette fonction.

Syntaxe d'une docstring

PYTHON
def multiplier(a: int, b: int) -> int:
    """Multiplie deux nombres entiers et retourne le résultat."""
    return a * b

Comme on peut le voir dans notre exemple, une docstring doit être :

  • délimitée par trois guillemets doubles """ ou trois guillemets simples ''' ;
  • rédigée de manière claire et concise ;
  • respecter les conventions de la PEP 257.

 

Exemple complet d'une docstring sur une fonction

PYTHON
def calcul_aire_rectangle(longueur: float, largeur: float) -> float:
    """
    Calcule l'aire d'un rectangle.

    Paramètres :
    - longueur : float, la longueur du rectangle
    - largeur : float, la largeur du rectangle

    Retour :
    - float : l'aire calculée
    """
    return longueur * largeur

Pas mal non ? 😊

Les docstrings sont lues automatiquement par help() et les IDE (les éditeurs de code). Elles améliorent grandement la compréhension du code, surtout en travail collaboratif.

 

La portée des variables dans une fonction (scope)

La portée d’une variable désigne l’endroit du programme où cette variable est accessible.

En Python, les variables définies dans une fonction ne sont pas accessibles en dehors.

Les variables locales

Il s'agit d'une variable créée à l’intérieur d’une fonction.

PYTHON
def dire_bonjour():
    message = "Bonjour"
    print(message)

print(message) # Erreur car message n'existe que pour dire_bonjour()

 

Les variables globales

Une variable définie à l’extérieur de toute fonction est globale, donc visible dans tout le programme... mais pas modifiable depuis une fonction sans utiliser le mots-clé global.

PYTHON
nom = "Alice"

def changer_nom():
    global nom
    nom = "Bob"

changer_nom()
print(nom)  # Bob

L’usage de global est souvent déconseillé car cela rend le code plus difficile à suivre. Il est préférable de retourner une valeur et de la stocker.

 

Les fonctions imbriquées (nested functions)

En Python, il est possible de définir une fonction à l’intérieur d’une autre fonction. C'est justement ce qu'on appelle une fonction imbriquée. 👀

Prenons un exemple :

PYTHON
def exterieur():
    def interieur():
        return "Bonjour depuis l’intérieur !"
    return interieur()

Dans notre exemple, il faut appeler exterieur() qui va appeler interieur() pour retourner notre chaîne de caractères.

Ok c'est super, mais à quoi ça sert ?

À beaucoup de choses ! 🥸

On peut par exemple :

  • encapsuler une logique qui ne sera utilisée qu'à un endroit précis ;
  • créer des fonctions fermées (closures) ;
  • améliorer la lisibilité dans certains cas complexes.

 

Les fonctions récursives

Comme nous l'avons vu, les fonctions peuvent s'imbriquer.

Grâce à cette possibilité, nous pouvons créer ce qu'on appelle des fonctions récursives.

Une fonction récursive est une fonction qui s'appelle elle-même. C’est utile pour résoudre des problèmes de manière décomposée, comme les calculs de factorielle, de suites, ou de parcours d’arborescences.

Voici un exemple très classique :

PYTHON
def factorielle(n):
    if n == 0:
        return 1
    else:
        return n * factorielle(n - 1)

print(factorielle(5))  # 120

Une récursion mal contrôlée peut provoquer un dépassement de pile (RecursionError). Assurez-vous d’avoir un cas de sortie. Autrement, vous allez créer une boucle infinie (ce qui fera planter votre code) !

 

Les fonctions sont des objets

En Python, les fonctions sont considérées comme des objets.

Ceci veut dire qu'il est possible de les assigner à des variables, de les passer en paramètre ou encore de les stocker dans des listes par exemple.

Voici chacun des cas dans des petits exemples !

Assigner une fonction à une variable

PYTHON
def bonjour():
    return "Salut !"

dire = bonjour
print(dire())  # Salut !

ici, on assigne la fonction bonjour à notre variable dire. Autrement dit, on peut désormais executer dire comme une fonction !

 

Passer une fonction comme argument

PYTHON
def appliquer(fonction, valeur):
    return fonction(valeur)

def doubler(x):
    return x * 2

resultat = appliquer(doubler, 5)
print(resultat)  # 10

Dans cet exemple, on passe la fonction doubler dans notre fonction appliquer : c'est très utilisé pour décomposer nos fonctions en plusieurs petites fonctions.

 

Stocker dans une liste

PYTHON
def a(): return "A"
def b(): return "B"

fonctions = [a, b]
for f in fonctions:
    print(f())  # A puis B

Dans cet exemple, on assigne les fonctions a et b dans une liste pour pouvoir les réutiliser plus tard (dans une boucle ici).

 

Les fonctions génératrices avec yield

Il est également possible d'utiliser ce qu'on appelle des générateurs.

Ce sont des fonctions spéciales qui utilisent le mot-clé yield au lieu de return.

Ils retournent toujours un élément à la fois, ce qui permet de gérer de grands volumes de données sans tout charger en mémoire. Petit bonus : ils conversevent l'état d'exécution entre chaque appel !

Par exemple :

PYTHON
def compte():
    for i in range(3):
        yield i

for nombre in compte():
    print(nombre)  # 0, 1, 2

yield suspend l’exécution de la fonction et la reprend au même endroit lors du prochain appel.

 

Les décorateurs sur les fonctions

Les décorateurs sont des fonctions qui modifient ou enrichissent une autre fonction sans la modifier directement. Ils sont très utilisés dans les frameworks comme Flask ou Django.

Ils prennent une fonction en argument et retournent une fonction modifiée.

Ils sont très utilisés dans des contextes comme la journalisation, la validation d'entrée ou encore l'authentification.

Prenons un exemple très simple : imaginez que vous souhaitiez afficher "== Début ==" et "== Fin ==" à chaque appel d’une fonction sans changer son code. Plutôt que de modifier toutes vos fonctions, vous utilisez un décorateur.

PYTHON
def afficher_balises(fonction):
    def wrapper():
        print("== Début ==")
        fonction()
        print("== Fin ==")
    return wrapper

@afficher_balises
def dire_bonjour():
    print("Bonjour à tous !")

dire_bonjour()

Ce qu'il se passe en boulisses :

  • def afficher_balises(fonction) : une fonction qui prend une autre fonction en paramètre ;
  • à l’intérieur, nous définissons wrapper() qui appelle la fonction originale tout en ajoutant du code avant et après ;
  • en appliquant @afficher_balises avant une autre fonction, Python exécute notre décorateur en passant en argument la fonction dire_bonjour() définie juste après !

Les décorateurs rendent donc notre code plus modulaire et réutilisable, tout en gardant vos fonctions propres.

 

Fonctions anonymes (lambda) vs nommées

En Python, il existe deux façons principales de définir des fonctions :

  • avec des fonctions anonymes appelées aussi fonctions lambda ;
  • ou avec des fonctions nommées qu'on appelle aussi des fonctions traditionnelles (ce qu'on voit justement ici).

Tableau comparatif

Type de fonctionSyntaxeCas d'usage principal
Nommée (def)def nom():Factorisation et documentation
Anonyme (lambda)lambda args: exprOpérations ponctuelles et uniques

 

Exemples comparés

PYTHON
# Fonction nommée
def ajouter(x, y):
    return x + y

# Fonction lambda équivalente
lambda_ajouter = lambda x, y: x + y

Préférez def quand la fonction est complexe, longue ou utilisée plusieurs fois.

 

Bonnes pratiques d'écriture avec def

Plusieurs bonnes pratiques sont nécessaires pour faire des fonctions qui respectent les conventions en Python.

Pour commencer, il faut utiliser des noms clairs et éviter les noms trop vagues :

  • calculer_aire_triangle(base, hauteur) est très représentatif ;
  • c(x, y) est beaucoup trop abstrait.

Il convient aussi de respecter la norme PEP 8, autrement dit :

  • il faut mettre deux lignes vides entre les définitions de fonctions (sauf dans les classes) ;
  • et il faut nommer les fonctions avec des mots en minuscules séparés par des underscores.

 

Erreurs courantes avec def

Faisons un petit tour des erreurs les plus courantes quand on crée des fonctions avec def en Python.

Oublier le return

PYTHON
def calcul(x, y):
    x + y  # Rien n’est retourné !

print(calcul(2, 3))  # Affiche : None

Il faut bien penser à ajouter le mot-clé return :

PYTHON
def calcul(x, y):
    return x + y

 

Avoir une mauvaise indentation

PYTHON
def test():
print("Bonjour")  # Erreur d’indentation !

Une mauvaise indentation empêche Python de comprendre quand s'arrête une fonction.

PYTHON
def test():
    print("Bonjour")

 

Oublier les parenthèses pour appeler une fonction

PYTHON
def bonjour():
    return "Salut"

print(bonjour)   # Erreur

C'est une erreur classique ! 👀

PYTHON
def bonjour():
    return "Salut"

print(bonjour())   # Les parenthèses sont ajoutées

 

Questions fréquentes sur def

Peut-on avoir plusieurs return ?

Oui. Cela permet de renvoyer différentes valeurs selon les conditions.

 

Doit-on typer toutes les fonctions ?

Non, comme nous l'avons vu ensemble les annotations de type sont facultatives.

 

Qu'est-ce qu'une fonction récursive ?

Une fonction qui s'appelle elle-même. Elle permet de traiter des problèmes de manière décomposée.

 

Comment se former à Python ?

En rejoignant notre formation Python !

Découvrez notre glossaire Python

Parcourez les termes et définitions les plus couramment utilisés dans le domaine du développement avec Python.