Section 4.6

Fonctions

Dans cette section, nous allons apprendre à définir et à utiliser nos propres fonctions. Une fonction est un morceau de code auquel on donne un nom et parfois des paramètres. Lorsqu'on appelle une fonction, le code qui se trouve dans la fonction est exécuté.

Définir des fonctions

En Python, on définit une fonction avec le mot-clé def. On donne ensuite un nom à la fonction, puis on écrit une paire de parenthèses. Comme nous le verrons plus tard, c'est entre ces parenthèses que l'on indiquera les paramètres de la fonction. Enfin, on termine la ligne avec un deux-points : et on écrit le corps de la fonction à l'aide d'un bloc indenté en dessous de cette première ligne.

Par exemple, voici la définition d'une fonction qui affiche un message de bienvenue :

def bienvenue(): print("Bienvenue dans ce programme !") print("Amusez-vous bien !")

Si on exécute ce programme, on voit que rien ne se passe. C'est tout à fait normal, car on a uniquement définit la fonction bienvenue, mais on ne l'a pas encore appelée.

Appeler des fonctions

Pour appeler une fonction, on écrit son nom suivi d'une paire de parenthèses, comme à la ligne 11 du programme suivant :

def bienvenue(): print("Bienvenue dans ce programme !") print("Amusez-vous bien !") # Le corps de la fonction se termine ici. # En effet, la suite du code n'est pas indentée. # La fonction bienvenue est maintenant définie. # On appelle la fonction bienvenue. # Cela a pour effet d'exécuter le code qui se trouve dans le corps de la fonction. bienvenue()

Lorsque Python calcul la valeur d'un appel de fonction, il exécute le code qui se trouve dans la fonction.

Les fonctions peuvent être appelées à plusieurs reprises. Par exemple, dans le programme suivant, on appelle la fonction rires à deux endroits différents du code. Au deuxième endroit dans le code, comme l'appel apparaît dans une boucle, l'appel donne même lieu à trois exécutions consécutives de la fonction lors de l'exécution du programme. Voyez-plutôt :

def rires(): print("HAHAHAHA !") print("Qu'est-ce qu'un canif ?") rires() input("Appuyez sur Entrée pour continuer..."") print("Un petit fien !") for i in range(3): rires()

! Remarque

On utilise le terme d'appel de fonction pour faire référence à deux concepts relativement similaires mais qu'il est intéressant de distinguer :

  • Au moment de l'écriture du code, on dit qu'on appelle une fonction lorsqu'on écrit son nom suivi d'une paire de parenthèses dans le code d'un programme.
  • Au moment de l'exécution du code, on dit aussi qu'on appelle une fonction lorsqu'on exécute la fonction.
Le premier concept est un concept syntaxique (qui a trait à l'écriture du programme), tandis que le second a trait à l'exécution du programme. Un unique appel de fonction (le premier concept) peut donner lieu à plusieurs appels de la fonction (le second concept) au moment de l'exécution du programme, comme dans l'exemple ci-dessus.

Paramètres et arguments

Lorsqu'on définit une fonction, on peut lui donner des paramètres. Ces paramètres sont des variables qui sont créées à l'intérieur de la fonction. On indique les paramètres de la fonction entre les parenthèses de la définition de la fonction, séparés par une virgule. On peut alors utiliser ces paramètres dans le corps de la fonction.

def dire_bonjour(nom): # Le paramètre est nom print("Bonjour", nom, "!") # On peut utiliser nom dans le corps de la fonction dire_bonjour("Albert") # L'argument est "Albert" dire_bonjour("Berthe") # L'argument est "Berthe" nom_utilisateur = input("Quel est votre nom ? ") dire_bonjour(nom_utilisateur) # L'argument est la valeur de la variable nom_utilisateur

À noter que lorsque l'on définit la fonction, on ne connait pas les valeurs de ces paramètres. C'est lorsqu'on appelle la fonction que l'on donne les valeurs de ces paramètres pour l'appel en question via les arguments de l'appel. Chaque appel peut avoir des arguments différents.

Lorsque l'on appelle une fonction à plusieurs paramètres, on doit donner autant d'arguments que de paramètres. Les arguments sont donnés dans le même ordre que les paramètres. Par exemple, dans le programme suivant, la fonction dire_bonjour a deux paramètres : nom et vouvoyer. Lorsqu'on appelle la fonction, on doit donc donner deux arguments : le nom de la personne et si on doit la vousoyer.

def dire_bonjour(nom, vouvoyer): # La fonction a deux paramètres : nom et vouvoyer print("Bonjour", nom, "!") if vouvoyer: print("Comment allez-vous ?") else: print("Comment vas-tu ?") dire_bonjour("Albert", False) # Ici, on donne "Albert" et False comme arguments dire_bonjour("Berthe", True) # Ici, on donne "Berthe" et True comme arguments

Passage par valeur

Dans Python, les arguments d'un appel de fonction sont passés par valeur à la fonction. Les arguments sont tout d'abord calculés, puis ensuite ils sont passés à la fonction.

Lorsque l'on passe une variable comme argument à une fonction, uniquement la valeur de la variable est passée à la fonction, et non la variable elle-même. Si la fonction modifie la valeur d'un paramètre au sein de son corps, cela n'affecte donc pas la valeur des éventuelles variables passées en argument. Observez l'exemple suivant :

def doubler(x): x = x * 2 # On modifie la valeur de x, le paramètre print(x) # On affiche la nouvelle valeur de x a = 5 # On crée une variable a doubler(a) # On appelle la fonction avec a comme argument print(a) # On affiche la valeur de a, qui n'a pas changé # Même si le nom est le même, c'est une autre variable # qui est créée dans la fonction pour le paramètre x # Par exemple: x = 8 # On crée une variable x doubler(x) # On appelle la fonction avec x comme argument print(x) # On affiche la valeur de x, qui n'a pas changé

Retourner une valeur

Par défaut, une fonction ne retourne aucune valeur. Si on affiche la valeur de l'appel d'une telle fonction, on obtient None.

def dire_bonjour(nom): print("Bonjour", nom, "!") print(dire_bonjour("Albert"))

! Remarque

On parle de procédure lorsqu'une fonction ne retourne aucune valeur utile. Généralement, on utilise les procédures pour leurs effets de bord. Par exemple, la fonction print est une procédure, tout comme la fonction dire_bonjour ci-dessus. On n'utilise pas leur résultat dans des calculs, mais on les appelle juste pour leurs effets de bord.

Il est possible de faire en sorte qu'une fonction retourne une valeur. Cette valeur est alors utilisée comme la valeur de l'appel de la fonction au sein des calculs effectués par le programme. Pour spécifier la valeur de retour d'une fonction, on utilise le mot-clé return, suivi de la valeur de retour, comme dans l'exemple suivant :

def carre(x): return x * x print(carre(3)) print(carre(5) * 2)

Lorsque Python rencontre le mot-clé return lors de l'exécution d'une fonction, il arrête immédiatement l'exécution du corps de la fonction et utilise la valeur donnée comme valeur de retour de la fonction. Cette valeur de retour est alors utilisée comme la valeur de l'appel de fonction.

def valeur_absolue(x): if x < 0: return -x return x print(valeur_absolue(-3) + valeur_absolue(5))

Dans le programme précédent, on a utilisé une instruction conditionnelle pour vérifier si la valeur de x est négative. Si c'est le cas, on retourne la valeur de -x et on arrête l'exécution de la fonction. Autrement, lorsque x n'est pas négatif, on ne rentre pas dans le bloc de l'instruction conditionnelle. On passe donc directement à l'instruction suivante, où l'on retourne la valeur de x.

! Remarque

Lorsqu'une fonction retourne une valeur et n'a aucun effet de bord visible depuis l'extérieur de la fonction, on parle de fonction pure. Par exemple, la fonction valeur_absolue ci-dessus est une fonction pure, tout comme les fonctions max et min définies de base en Python. En revanche, la fonction input n'est pas une fonction pure, car elle a un effet de bord visible depuis l'extérieur (l'affichage à l'écran et la lecture de l'entrée utilisateur).

Pourquoi retourner une valeur ?

Étant donné l'existence de la fonction print, on pourrait se demander pourquoi on a besoin de retourner une valeur depuis une fonction. En effet, ne serrait-il pas plus simple de faire en sorte que la fonction affiche directement le résultat de son calcul avec print ?

Retourner une valeur à la place de l'afficher permet de faire des calculs avec le résultat d'une fonction, ce qu'il n'est pas possible de faire si on affiche directement le résultat.

def carre(x): return x * x print(carre(3) + carre(5)) # On ne peut pas faire ça avec print. # La fonction print affiche directement le résultat, # mais ne permet pas de le récupérer pour l'utiliser # dans la suite du programme. def carre_2(x): print(x * x) print(carre_2(3) + carre_2(5))

De plus, on ne souhaitera pas toujours afficher le résultat d'une fonction. Si un programme venait à afficher tous les résultats de toutes les fonctions qu'il appelle, il serait difficile de distinguer quoi que ce soit dans la sortie.

Portée des paramètres et des variables

Les paramètres et les variables définies dans le corps d'une fonction sont uniquement accessibles dans le corps de la fonction. On dit que ces variables ont une portée locale. Par exemple, dans le programme suivant, le paramètre nom n'est pas accessible en dehors de la fonction dire_bonjour.

def dire_bonjour(nom): print("Bonjour", nom, "!") dire_bonjour("Albert") print(nom)

Lorsqu'on exécute le code ci-dessus, Python émet une erreur à l'exécution de la dernière ligne, car la variable nom n'est pas définie. En effet, la variable nom n'est définie que dans le corps de la fonction dire_bonjour (sous forme d'un paramètre). Après l'exécution de la fonction, cette variable nom n'existe plus. L'effet est le même si on définit une variable via une assignation dans le corps de la fonction :

def dire_bonjour(): nom = "Berthe" print("Bonjour", nom, "!") dire_bonjour() print(nom)

Lorsque l'on définit un paramètre ou une variable dans le corps d'une fonction, il est possible de réutiliser le même nom qu'une variable définie en dehors de la fonction. Dans ce cas, la variable définie dans le corps de la fonction masque la variable définie en dehors de la fonction. Pour le temps de l'appel de la fonction, la variable définie en dehors de la fonction n'est plus accessible.

# Une variable nom est définie en dehors de la fonction. nom = "Albert" def dire_bonjour(nom): # Le paramètre nom masque la variable nom définie hors de la fonction. print("Bonjour", nom, "!") dire_bonjour("Berthe") # La variable nom définie en dehors est de nouveau accessible. # Elle n'a pas été modifiée par l'appel de la fonction. # En effet, il s'agit de deux variables différentes. print(nom)

Notez qu'il est possible d'utiliser une variable définie en dehors de la fonction dans le corps de la fonction pour autant qu'aucune paramètre ou variable locale n'ait pas le même nom.

nom_programme = "Super programme 3000" def dire_bonjour(nom): print("Bonjour", nom, "!") # nom est un paramètre print("Bienvenue dans", nom_programme) # nom_programme est définie hors de la fonction dire_bonjour("Caroline") nom_programme = "Super programme 3000, v2" dire_bonjour("Délphine")

! Remarque

On parle de variables globales pour les variables définies en dehors de toute fonction. Au contraire, on parle de variables locales pour les variables définies dans le corps d'une fonction. Les paramètres d'une fonction sont des variables locales. Toutes les utilisations d'un nom de variable au sein d'une fonction font référence à la même variable, qu'elle soit locale ou globale.

Pour déterminer si une variable est locale ou globale au sein d'une fonction, Python se base sur un critère syntaxique : s'il existe une instruction d'assignation de la variable dans le code du corps de la fonction, alors tous les usages font référence à la variable locale. Notez que cette assignation n'a même pas besoin d'être exécutée, il suffit qu'elle soit écrite quelque part dans le code de la fonction. Dans le cas où il n'y a aucune instruction d'assignation de la variable dans le corps de la fonction, et que la variable n'est pas un paramètre de la fonction, alors les usages de la variable font référence à la variable globale.

nom = "Albert" def dire_bonjour(dire_prenom): if not dire_prenom: nom = "inconnu" print("Bonjour", nom, "!") dire_bonjour(False) dire_bonjour(True)

Dans l'exemple précédent, comme il existe une instruction d'assignation de la variable nom dans le corps de la fonction (à la ligne 4), cette variable est considérée comme locale. À la ligne 5, c'est donc la variable locale qui est utilisée, et non la variable globale, et ce même si l'assignation de la variable locale n'a pas été exécutée. On obtient donc une erreur lors de l'appel de la fonction dire_bonjour à la ligne 8, car la variable nom n'est pas définie pour cet appel.

! Remarque

Il est possible, mais souvent déconseillé, de modifier une variable globale depuis une fonction. En Python, on peut le faire en utilisant le mot-clé global comme dans l'exemple suivant :

nom_programme = "Super programme 3000" def dire_bonjour(nom): global nom_programme nom_programme = "Super programme 3001" print("Bonjour", nom, "!") print("Bienvenue dans", nom_programme) dire_bonjour("Caroline") print(nom_programme)

Dans l'exemple précédent, on a modifié la valeur de la variable globale nom_programme depuis le corps de la fonction dire_bonjour.

De manière générale, il est préférable de ne pas modifier les variables globales depuis les fonctions. En effet, cela peut rendre le code difficile à comprendre et à faire évoluer.

Les fonctions, un outil de conception très puissant

Les fonctions sont un outil de conception très puissant. Elles permettent de décomposer le problème parfois complexe de la conception d'un programme en sous-problèmes plus simples. Lorsque l'on écrit un programme, on peut ainsi se concentrer sur un sous-problème à la fois, à la conception d'une fonction à la fois. Ensuite, on peut combiner ces fonctions pour obtenir un programme complet.

Les fonctions sont également un moyen de faire abstraction des détails d'implémentation. En effet, lorsqu'on utilise une fonction, on n'a pas besoin de connaître les détails de son implémentation. On peut penser à une fonction de manière très abstraite, en se concentrant sur ce qu'elle fait, et non sur la manière dont elle le fait. Cela permet de rendre le code plus facile à comprendre et à modifier.

Finalement, les fonctions permettent de réutiliser du code. En effet, définir une fonction c'est essentiellement donner un nom à un morceau de code que l'on peut ensuite réutiliser à plusieurs endroits dans un programme. Cela permet de réduire la quantité de code à écrire et donc de réduire le risque d'erreurs.

Auto-évaluation

En Python, on utilise le mot-clé pour définir une fonction.

On utilise pour délimiter syntaxiquement le corps d'une fonction.

Auto-évaluation

Les variables définies dans le corps d'une fonction sont appelées , tandis que les variables définies en dehors de toute fonction sont appelées . Les paramètres d'une fonction sont des .

Au sein d'une fonction, on peut utiliser des variables globales ainsi que les modifier en utilisant le mot-clé .

Auto-évaluation

Pour renvoyer une valeur depuis une fonction, on utilise le mot-clé . Lors de l'exécution du code d'une fonction, lorsque Python rencontre ce mot-clé, il de la fonction. La valeur renvoyée par la fonction est celle qui suit le mot-clé.

Une fonction qui ne renvoie pas de valeur et est uniquement utilisée pour ses effets de bord est appelée . Au contraire, une fonction sans effet de bord est appelée . Pour une telle fonction, la valeur renvoyée ne dépend que des arguments passés à la fonction.

Dans cette section, nous avons vu comment définir et appeler des fonctions en Python. Nous avons vu comment définir des fonctions avec des paramètres, ainsi que comment renvoyer une valeur depuis une fonction.

Dans la section suivante, nous allons voir comment manipuler des séquences de données comme les listes et les chaînes de caractères en Python.