10 - Fonctions

Pourquoi les fonctions ?

Lorsqu’un programme devient long, on se retrouve souvent à copier-coller des blocs de code similaires. Cela pose plusieurs problèmes : le code est difficile à lire, et si l’on doit corriger une erreur, il faut la corriger partout où le bloc a été copié.

Les fonctions permettent de regrouper un ensemble d’instructions sous un nom, puis de les exécuter autant de fois qu’on le souhaite en une seule ligne. C’est le principe fondamental de la décomposition d’un problème en sous-problèmes.

Définir et appeler une fonction

On définit une fonction avec le mot-clé def, suivi du nom de la fonction et de parenthèses :

def dire_bonjour():
    print("Bonjour !")
    print("Bienvenue en NSI")

Pour exécuter le code de la fonction, on l’appelle en écrivant son nom suivi de parenthèses :

dire_bonjour()
dire_bonjour()
Bonjour !
Bienvenue en NSI
Bonjour !
Bienvenue en NSI

Attention : la définition d’une fonction (def ...) n’exécute rien. Le code de la fonction ne s’exécute que lorsqu’on l’appelle.

Fonctions avec paramètres

Les paramètres permettent de personnaliser le comportement d’une fonction. On les déclare entre les parenthèses :

def saluer(prenom):
    print(f"Bonjour {prenom} !")

saluer("Alice")
saluer("Bob")
Bonjour Alice !
Bonjour Bob !

Une fonction peut avoir plusieurs paramètres, séparés par des virgules :

def presenter(prenom, age):
    print(f"{prenom} a {age} ans")

presenter("Alice", 17)
presenter("Bob", 16)
Alice a 17 ans
Bob a 16 ans

Paramètres et arguments

En toute rigueur, on distingue les paramètres (les noms dans la définition) des arguments (les valeurs passées lors de l’appel). Mais en pratique, les deux termes sont souvent utilisés de façon interchangeable.

La valeur de retour : return

Fonctions qui renvoient un résultat

Une fonction peut calculer une valeur et la renvoyer grâce à l’instruction return :

def carre(n):
    return n ** 2

resultat = carre(5)
print(resultat)        # 25
print(carre(3) + 1)    # 10

L’instruction return met fin à l’exécution de la fonction : tout ce qui suit dans le corps de la fonction est ignoré.

def valeur_absolue(n):
    if n >= 0:
        return n
    return -n

print(valeur_absolue(7))    # 7
print(valeur_absolue(-3))   # 3

Fonctions sans return

Une fonction qui n’a pas de return (ou qui a un return sans valeur) renvoie automatiquement None :

def afficher_resultat(note):
    if note >= 10:
        print("Admis")
    else:
        print("Ajourné")

r = afficher_resultat(15)
print(r)    # None

Règle importante : une fonction qui affiche (print) et une fonction qui renvoie (return) ne font pas la même chose. Renvoyer une valeur est presque toujours préférable, car cela permet de la réutiliser dans d’autres calculs.

Valeurs par défaut

On peut donner une valeur par défaut à un paramètre. Si l’argument n’est pas fourni lors de l’appel, la valeur par défaut est utilisée :

def saluer(prenom, formule="Bonjour"):
    print(f"{formule} {prenom} !")

saluer("Alice")                # Bonjour Alice !
saluer("Alice", "Bonsoir")     # Bonsoir Alice !

Règle : les paramètres avec valeur par défaut doivent être placés après les paramètres obligatoires.

Arguments nommés

Lors de l’appel, on peut préciser le nom des paramètres pour plus de clarté ou pour changer l’ordre :

def rectangle(largeur, hauteur):
    return largeur * hauteur

print(rectangle(5, 3))                    # 15
print(rectangle(hauteur=3, largeur=5))    # 15 (ordre inversé)

Portée des variables

Variables locales

Les variables créées à l’intérieur d’une fonction sont locales : elles n’existent que pendant l’exécution de la fonction et sont détruites ensuite.

def calculer():
    x = 10    # variable locale
    print(f"Dans la fonction : x = {x}")

calculer()
# print(x)  # NameError : x n'existe pas ici

Variables globales

Les variables définies en dehors de toute fonction sont globales : elles sont accessibles partout en lecture.

message = "Bonjour"   # variable globale

def afficher():
    print(message)     # on peut LIRE une variable globale

afficher()    # Bonjour

Variable locale qui masque une variable globale

Si une fonction définit une variable portant le même nom qu’une variable globale, la variable locale masque la globale sans la modifier :

x = 100   # variable globale

def modifier():
    x = 0  # variable locale : ne modifie PAS le x global
    print(f"Dans la fonction : x = {x}")

modifier()
print(f"Hors de la fonction : x = {x}")
Dans la fonction : x = 0
Hors de la fonction : x = 100

Bonne pratique : évitez de donner le même nom à une variable locale et à une variable globale. Privilégiez le passage par paramètres et valeur de retour.

Documenter une fonction : les docstrings

Une docstring est une chaîne de caractères placée juste après la ligne def. Elle décrit ce que fait la fonction :

def moyenne(notes):
    """Calcule et renvoie la moyenne d'une liste de notes."""
    return sum(notes) / len(notes)

On peut consulter la docstring d’une fonction avec help() :

help(moyenne)
Help on function moyenne in module __main__:

moyenne(notes)
    Calcule et renvoie la moyenne d'une liste de notes.

Fonctions comme objets

En Python, les fonctions sont des objets comme les autres. On peut les stocker dans des variables ou les passer en paramètre :

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

print(appliquer(carre, 5))    # 25
print(appliquer(len, "NSI"))  # 3

Résumé

ConceptSyntaxeExemple
Définitiondef nom(params):def carre(n):
Retourreturn valeurreturn n ** 2
Appelnom(arguments)carre(5)25
Valeur par défautparam=valeurdef f(x, y=0):
Docstring"""description""""""Calcule le carré."""

Points essentiels à retenir :

  • une fonction regroupe un bloc de code réutilisable ;
  • return renvoie une valeur ; sans return, la fonction renvoie None ;
  • les variables créées dans une fonction sont locales ;
  • toujours documenter ses fonctions avec une docstring.