Rappels sur les fonctions en Python

Objectifs et prérequis

Prérequis : bases de Python vues en première (variables, boucles, conditions)

À l’issue de ce chapitre, vous saurez :

  • définir et appeler une fonction avec des paramètres positionnels, par mots-clé et par défaut ;
  • expliquer la portée locale des variables et le mot-clé global ;
  • utiliser *args et **kwargs pour un nombre variable de paramètres ;
  • passer une fonction comme paramètre d’une autre fonction ;
  • vérifier les préconditions avec assert et documenter les fonctions avec des docstrings.

Introduction

Les fonctions sont un moyen efficace de structurer un programme et de l’organiser en modules. Le choix du nom d’une fonction est important pour la lisibilité du programme. En Python, une fonction est définie à l’aide du mot-clé def.

def ma_fonction():
    print("Les fonctions en Python sont faciles à apprendre")

ma_fonction()
Les fonctions en Python sont faciles à apprendre

À noter que l’appel s’effectue par ma_fonction() au lieu de print(ma_fonction()) car ma_fonction utilise le mot-clé print au lieu de return.

Portée locale des variables

Lorsqu’une nouvelle variable est affectée à l’intérieur du corps de la fonction, elle n’est définie qu’à l’intérieur de la fonction. La variable n’est pas visible en dehors de la fonction. Nous pouvons donc choisir n’importe quel nom lors de la définition des variables sans nous soucier des variables extérieures à la fonction.

Par exemple :

x = 10 # x est une variable globale
y = 10 # y aussi

def une_fonction():
    x = 5 # x est une variable locale
    global y # Ceci permet de modifier la valeur de la variable globale y
    y = 5
print(x)
print(y)
une_fonction()
print(x)
print(y)
10
10
10
5

La variable x ne change pas en dehors de la fonction puisque la portée de x définie à l’intérieur de la fonction est limitée à la fonction elle-même. Seul le mot-clé global permet de modifier la valeur d’une variable globale.

À ce sujet, voir cette vidéo :

Type de paramètres

Les paramètres, sont utilisés pour transmettre des informations dans une fonction.

Soit la fonction fraction suivante :

def fraction(numerateur, denominateur):
    print(f"{numerateur}/{denominateur}")

Il existe plusieurs façons de passer les paramètres :

Paramètres positionnels

Dans la fonction fraction, les paramètres numerateur et denominateur sont appelés paramètres positionnels (en anglais positional arguments). Il est strictement obligatoire de les préciser lors de l’appel de la fonction. De plus, il est nécessaire de respecter le même ordre lors de l’appel que dans la définition de la fonction. Dans l’exemple ci-dessous, 10 correspond à numerateur et 4 correspond à denominateur.

fraction(10, 4)

fraction(*(10, 4))
fraction(*[10, 4])
10/4
10/4
10/4

Paramètres par mots-clé

Un paramètre défini avec une syntaxe def fonction(param=val): est appelé paramètre par mot-clé (en anglais keyword argument). Le passage d’un tel paramètre lors de l’appel de la fonction est facultatif. Ce type de paramètre ne doit pas être confondu avec les paramètres positionnels présentés ci-dessus, dont la syntaxe est def fonction(param):.

fraction(numerateur=10, denominateur=4)

fraction(**{'numerateur': 10, 'denominateur': 4})
10/4
10/4

Paramètres par défaut

Il est possible de préciser des valeurs par défaut pour certains paramètres. Comme leur nom l’indique, ces valeurs seront utilisées par défaut lors d’un appel à la fonction si aucune valeur effective (si aucun paramètre) n’est passée à la place.

Utiliser des valeurs par défaut pour les paramètres de fonctions permet donc aux utilisateurs d’appeler cette fonction en omettant de passer les paramètres possédant des valeurs par défaut.

def presentation(prenom, age=15, ville="Lyon"):
    print(
        f"Je m'appelle {prenom}, j'ai au moins {age} ans et j'habite à {ville}."
    )


presentation("Gaudric")
presentation("Faustin", 19)
presentation("Justine", 21, "Paris")
presentation("Audrey", ville="Toulouse")
presentation(age=20, ville="Strasbourg", prenom="Augustin")
Je m'appelle Gaudric, j'ai au moins 15 ans et j'habite à Lyon.
Je m'appelle Faustin, j'ai au moins 19 ans et j'habite à Lyon.
Je m'appelle Justine, j'ai au moins 21 ans et j'habite à Paris.
Je m'appelle Audrey, j'ai au moins 15 ans et j'habite à Toulouse.
Je m'appelle Augustin, j'ai au moins 20 ans et j'habite à Strasbourg.

Nombre variable de paramètres

Complément hors programme. Les syntaxes *args et **kwargs ne sont pas exigibles au baccalauréat, mais on les rencontre dans la documentation des bibliothèques.

La syntaxe *args (remplacez args par ce que vous voulez) permet d’indiquer lors de la définition d’une fonction qu’elle peut accepter un nombre variable de paramètres. Ces paramètres sont intégrés dans un tuple. On va pouvoir préciser zéro, un ou plusieurs paramètres classiques dans la définition de la fonction avant la partie variable.

def aire_rectangle(*args):
    if len(args) == 2:
        return args[0] * args[1]
    else:
        print("Merci de stipuler deux paramètres")


print(aire_rectangle(3, 8))
24

De façon alternative, la syntaxe **kwargs (on peut remplacer kwargs par ce que l’on veut) permet également d’indiquer que la fonction peut recevoir un nombre variable de paramètres mais cette fois-ci les paramètres devront être passés sous la forme d’un dictionnaire Python.

def aire_rectangle2(**kwargs):
    if len(kwargs) == 2:
        result = 1
        for key, value in kwargs.items():
            result *= value
        return result
    else:
        print("Merci de stipuler deux paramètres")


print(aire_rectangle2(cote1=4, cote2=8))
32

Les syntaxes *args et **kwargs peuvent être utilisées pour réaliser les opérations inverse de celles présentés ci-dessus, à savoir séparer des données composites pour passer les valeurs ou éléments de ces données un à un en paramètres des fonctions. On, utilisera la syntaxe *args pour séparer les paramètres présents dans une liste ou un tuple et la syntaxe **kwargs pour séparer les paramètres présents dans un dictionnaire et fournir des paramètres nommés à une fonction.

def somme(a, b, c):
    s = a + b + c
    print(s)


ma_liste = [1, 2, 3]
# somme(ma_liste) # Erreur car la somme attend trois paramètres
somme(*ma_liste)


mon_dico = {'a': 1, 'b': 2, 'c': 3}
somme(**mon_dico)
6
6

Fonctions comme paramètres

On peut également passer une fonction comme paramètre. Par exemple, on peut passer la fonction intégrée len() ou une fonction définie par l’utilisateur voyelle_presente() comme paramètre à une autre fonction :

phrase = ['Les', 'fonctions', 'Python', 'sont', 'formidables']


def appliquer_fonction(prop):
    return [prop(mot) for mot in phrase]


print(appliquer_fonction(len))
def voyelle_presente(mot):
    for x in mot:
        if x in 'aeiouy':
            return True
    return False
print(appliquer_fonction(voyelle_presente))
[True, True, True, True, True]

Vérification du type des paramètres

Python n’oblige pas à spécifier le type des paramètres d’une fonction. Il est donc nécessaire de vérifier le type de variable d’entrée avant d’exécuter la fonction.

def est_une_voyelle(lettre):
    if lettre in 'aeiouy':
        return True
    return False


print(est_une_voyelle("poire"))
False

Pour éviter l’exécution et générer une erreur, on peut utiliser la fonction assert comme ceci.

def est_une_voyelle(lettre):
    assert (isinstance(lettre, str)), "La lettre doit être un caractère"
    assert (len(lettre) == 1), "La longueur de la lettre doit être de un !"
    if lettre in 'aeiouy':
        return True
    return False

print(est_une_voyelle("f"))
print(est_une_voyelle("poire"))
False
AssertionError: La longueur de la lettre doit être de un !

Si l’instruction assert échoue, elle produit une erreur, affiche le mesage correspondant et la fonction arrête l’exécution.

Documentation

Il est recommandé de documenter les fonctions : pour cela on utilise une docstring.

def est_une_voyelle(lettre):
    '''Prend en paramètre une chaîne de caractères de longueur un et retourne True si c'est une voyelle et False si ce n'est pas la cas'''
    assert (isinstance(lettre, str)), "La lettre doit être un caractère"
    assert (len(lettre) == 1), "La longueur de la lettre doit être de un!"
    if lettre in 'aeiouy':
        return True
    return False

La docstring de n’importe quelle fonction peut être affichée en exécutant la fonction help.

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

est_une_voyelle(lettre)
    Prend en paramètre une chaîne de caractères de longueur un et retourne True si c'est une voyelle et False si ce n'est pas la cas
Vérifiez votre compréhension
  1. Quelle est la différence entre return et print dans une fonction ?
    Réponsereturn renvoie une valeur que le programme peut utiliser (stocker dans une variable, passer à une autre fonction, etc.) et met fin à l'exécution de la fonction. print affiche simplement un texte à l'écran sans renvoyer de valeur exploitable (la fonction renvoie alors None).
  2. Que se passe-t-il si on modifie une variable x à l’intérieur d’une fonction sans utiliser global ?
    RéponsePython crée une variable locale du même nom, qui n'existe que dans la fonction. La variable globale x n'est pas modifiée. C'est la portée locale : les variables définies dans une fonction ne sont pas visibles à l'extérieur.
  3. Pourquoi utilise-t-on assert pour vérifier les paramètres d’une fonction ?
    RéponseLes assertions permettent de vérifier les préconditions : si un paramètre ne respecte pas les hypothèses de la fonction (mauvais type, valeur hors domaine…), le programme s'arrête immédiatement avec un message d'erreur explicite, au lieu de produire un résultat faux ou une erreur difficile à comprendre plus tard.
L'essentiel à retenir
  • Une fonction structure le code en unités réutilisables ; elle est définie avec def et renvoie une valeur avec return.
  • Les variables locales n’existent que dans la fonction ; seul global permet de modifier une variable extérieure (à éviter dans la mesure du possible).
  • Les paramètres peuvent être positionnels, par mots-clé ou par défaut ; *args et **kwargs permettent un nombre variable de paramètres.
  • Les assertions vérifient les préconditions ; les docstrings documentent le rôle, les paramètres et le comportement d’une fonction (consultables avec help()).
  • Les fonctions peuvent être passées comme paramètres d’autres fonctions, ce qui est à la base de la programmation fonctionnelle .

Elle peut également être affichée à l’aide de l’attribut __doc__.

print(est_une_voyelle.__doc__)
Prend en paramètre une chaîne de caractères de longueur un et retourne True si c'est une voyelle et False si ce n'est pas la cas