Médaille
N°1 pour apprendre & réviser du collège au lycée.
Fonctions et structure du code

Déjà plus de

1 million

d'inscrits !

Introduction :

Les fonctions sont des entités très utiles et très répandues en informatique. Elles sont utilisables dans la plupart des langages informatiques et correspondent même un style de programmation. Nous allons apprendre à définir et à utiliser des fonctions, puis à les paramétrer de différentes manières. Nous découvrirons ensuite les spécifications fonctionnelles ainsi que les bibliothèques de fonctions.

Définition et appel de fonctions

Nous allons dans un premier temps préciser le concept de fonction en sciences numériques et les différents types de fonctions. Nous verrons ensuite comment définir et utiliser une fonction.

Concept de fonction en informatique

En sciences numériques, une fonction est assez proche d'une fonction au sens mathématique du terme.

bannière definition

Définition

Fonction :

Une fonction est une portion de code informatique nommée, qui accomplit une tâche spécifique.

Les fonctions reçoivent généralement des données en entrée et retournent généralement en sortie le résultat du traitement opéré par la fonction.

Il est possible de créer et d'utiliser des fonctions dépourvues de paramètres d'entrée. Le langage Python permet également de créer des fonctions qui ne retournent rien mais exécutent ainsi des procédures de manière isolée et potentiellement répétée.

Types de fonctions

On distingue deux types de fonctions : les fonctions natives et les fonctions créées par l'utilisateur.

bannière definition

Définition

Fonction native :

Les fonctions natives sont des fonctions préprogrammées mises à la disposition du programmeur par les auteurs du langage.

Il est possible d'étendre les possibilités initiales du langage en créant des fonctions spécifiques pour répondre à des besoins particuliers.

bannière definition

Définition

Fonction définie par l'utilisateur :

Les fonctions définies par l'utilisateur sont des fonctions ajoutées par le programmeur aux fonctionnalités préprogrammées du langage.

Une fonction native est prête à l'emploi, tandis qu'une fonction définie par l'utilisateur doit d'abord faire l'objet d'une déclaration pour la définir.

Intérêt des fonctions

Les fonctions définies par l'utilisateur permettent d'enrichir le langage. L’emploi de fonctions permet de décomposer des tâches complexes en tâches élémentaires plus simples. Les fonctions présentent également l'intérêt de pouvoir être appelés plusieurs fois, ce qui évite de répéter des portions de code et facilite leur évolution ultérieure.

Modalités de définition d'une fonction

bannière à retenir

À retenir

Dans son expression la plus simple, une fonction consiste en une ligne de définition suivie par le bloc de code correspondant à cette fonction.

def fonction_elementaire():

pass # ne fait rien

Le mot-clé « def » indique à Python qu'une fonction va être définie. Ce mot-clé est suivi du nom de la fonction, de parenthèses pouvant éventuellement contenir des paramètres, et du signe « : ».

Le corps de la fonction suit immédiatement sous la forme d'un bloc de code indenté, c’est-à-dire dont la marge à gauche des lignes d’instruction se trouve supérieure à celle de la ligne qui introduit la définition de la fonction elle-même.

On veillera à choisir des noms de fonctions évocateurs de ce qu'elles réalisent, afin de faciliter la lecture du programme.

bannière exemple

Exemple

def bonjour():

return 'Bonjour'

Dans cette exemple, la fonction porte un nom évocateur. On observe qu'elle retourne un résultat, ici, la chaîne de caractères « Bonjour ».

Voyons maintenant comment utiliser cette fonction.

Modalités d'appel d'une fonction

L'appel d'une fonction s'effectue en indiquant son nom suivi des parenthèses ouvrantes et fermantes, ces dernières pouvant optionnellement contenir des valeurs comme nous le verrons par la suite.

print(bonjour())

# affiche la chaine de caractères "Bonjour"

On peut aussi stocker le résultat d'une fonction dans une variable :

texte = bonjour()

# n'affiche rien, affecte le résultat de la fonction à la variable texte

print(texte)

# affiche la chaine de caractères "Bonjour"

bannière attention

Attention

Si on omet les parenthèses après le nom d'une fonction, Python ne retourne pas le résultat de la fonction mais son adresse mémoire, c’est-à-dire l’endroit, dans la mémoire de l’ordinateur, où se trouve le début du code machine de la fonction  :

print(bonjour)

# affiche <function bonjour at 0x102b20378>

Les deux fonctions étudiées jusqu'à présent (« bonjour » et « fonction_elementaire ») ne comportaient aucun paramètre. Le paramétrage des fonctions étend grandement leur intérêt, comme nous allons le découvrir maintenant.

Paramétrage des fonctions

La définition de fonction peut inclure des paramètres qui seront utilisables au sein de la fonction.

Principe du paramétrage des fonctions

Les paramètres de la fonction sont indiqués entre parenthèses à la suite de son nom dans la ligne de définition de la fonction.

def bonjour(nom):

message = 'Bonjour ' + nom

return message

Le paramètre nom est une variable qui existe uniquement au sein de la fonction et le temps de l'exécution de celle-ci. La variable message est locale à la fonction, elle n'existe pas hors de celle-ci. Cette variable contient le résultat de la concaténation, c'est-à-dire de l'assemblage des deux chaînes de caractères.

On aurait pu directement retourner la chaîne concaténée sans l'étape intermédiaire d'affectation à une variable locale, mais la séparation des deux actions facilite la compréhension du code de la fonction.

L'appel de la fonction bonjour() modifiée s'effectue de la manière suivante :

print(bonjour('Alice'))

# affiche Bonjour Alice

Si une fonction comporte un paramètre dans sa définition, un argument doit être renseigné dans l’instruction d’appel de la fonction. Dans le cas contraire une erreur est générée.

print(bonjour())

# affiche le message d'erreur suivant :

Traceback (most recent call last):

File "fonctions.py", line 13, in

print(bonjour())

TypeError: bonjour() missing 1 required positional argument: 'nom'

Une fonction peut être définie avec plusieurs paramètres et donc recevoir plusieurs arguments.

Arguments multiples

Faisons évoluer notre fonction pour qu'elle soit capable de dire « bonjour » dans plusieurs langues. Nous ajoutons un paramètre langue dans la définition de la fonction et nous ajoutons dans le corps de celle-ci une série de tests conditionnels.

def bonjour(nom, langue):

if langue == 'français':

message = 'Bienvenue '

elif langue == 'anglais':

message = 'Hello '

elif langue == 'italien':

message = 'Ciao '

else:

message = 'Saluton '

message = message + nom

return message

Si la langue demandée n'est pas spécifiquement reconnue comme étant le français, l’anglais ou l’italien, c'est l'espéranto qui est choisi par notre fonction bonjour(), grâce à la condition « else » qui traite tous les cas autres que ceux prévus par les « if » et « elif ».

bannière rappel

Rappel

En Python :

  • le symbole d'égalité simple (=) est une affectation ;
  • le symbole double (==) effectue la comparaison d'une possible égalité qui vaut True si l'égalité est vraie et False sinon.

Les exemples ci-dessous illustrent le résultat produit par notre fonction pour différentes valeurs d'arguments.

print(bonjour('Paul', 'anglais'))

# affiche Hello Paul

print(bonjour('Alice', 'italien'))

# affiche Ciao Alice

print(bonjour('Alice', 'français'))

# affiche Bienvenue Alice

print(bonjour('Alice', 'zorglangue'))

# affiche Saluton Alice

On remarque que la « zorglangue » n’étant pas reconnue par la fonction, la réponse est affichée en espéranto.

Comme nous n'avons pas prévu l'emploi de majuscules, notre fonction répondrait aussi en espéranto si on lui indiquait « English » ou « ENGLISH » car ces chaines de caractères ne sont pas strictement identiques à « english » écrit tout en minuscules.

Valeurs par défaut

Nous avons imaginé notre fonction multilingue mais nous nous rendons compte à l'usage que nos messages sont la plupart du temps en français. Toutefois notre fonction ne nous permet pas actuellement d'omettre la langue.

print(bonjour('Alice'))

# affiche le message d'erreur suivant :

Traceback (most recent call last):

File "<stdin>", line 1, in <module>

TypeError: bonjour() missing 1 required positional argument: 'langue'

Nous allons donc faire évoluer notre fonction pour préciser la langue uniquement si elle est autre que le français.

def bonjour(nom, langue='français'):

if langue == 'français':

message = 'Bienvenue '

elif langue == 'anglais':

message = 'Hello '

elif langue == 'italien':

message = 'Ciao '

else:

message = 'Saluton '

message = message + nom

return message

Le corps de la fonction n’a pas changé : nous avons seulement précisé une valeur par défaut pour le paramètre langue dans la ligne de définition de la fonction, c’est-à-dire une valeur prise par le programme lorsqu’elle n’est pas explicitement fournie.

Vérifions que notre fonction ainsi modifiée produit bien le résultat attendu :

print(bonjour('Alice'))

# affiche Bienvenue Alice

Nous allons à nouveau faire évoluer notre fonction, en précisant également une valeur par défaut pour le nom : s'il n'est pas spécifié, on le nommera de manière générique « visiteur ».

def bonjour(nom='visiteur', langue='français'):

if langue == 'français':

message = 'Bienvenue '

elif langue == 'anglais':

message = 'Hello '

elif langue == 'italien':

message = 'Ciao '

else:

message = 'Saluton '

message = message + nom

return message

On notera à nouveau que le corps de la fonction n'a pas été modifié. Vérifions à présent le comportement de notre fonction après modification de son paramétrage.

print(bonjour())

# affiche Bienvenue visiteur

print(bonjour('Paul'))

# affiche Bienvenue Paul

print(bonjour('Claudia', 'italien'))

# affiche Ciao Claudia

Quand une fonction est définie avec des valeurs de paramètres par défaut, il devient possible de les omettre lors de l’appel. Il est également possible de les inclure nommément dans l'appel de la fonction.

print(bonjour(nom='Claudia', langue='italien'))

Le nommage des paramètres en arguments permet de s'affranchir de l'ordre dans lequel ils sont définis par la fonction.

print(bonjour(langue='italien', nom='Claudia'))

On préférera toutefois respecter l'ordre de définition afin de faciliter l'analyse du code (par soi-même ou par un tiers) plus tard. La documentation des fonctions présente le paramétrage dans l'ordre de définition.

Il est également possible de définir des fonctions contenant à la fois des paramètres sans valeur par défaut et des paramètres avec des valeurs par défaut.

Paramètres avec et sans valeurs par défaut

bannière à retenir

À retenir

Si une fonction comporte à la fois des paramètres sans et avec valeur par défaut, les paramètres sans valeur par défaut doivent impérativement précéder ceux disposant de valeurs par défaut dans la définition de la fonction.

De même, pour l'appel de la fonction, les arguments positionnels nécessitant obligatoirement des valeurs, doivent précéder les arguments optionnels correspondant aux paramètres dotés de valeurs par défaut.

Nous avons constaté que des erreurs d'exécution de nos fonctions pouvaient survenir dans certaines conditions. C'est notamment le cas si nous ne fournissons pas le nombre de paramètre requis, ou si nous fournissons des données inattendues par leur contenu ou par leur nature.

On comprend aisément qu'il n'est pas possible de calculer la racine carrée d'une chaine de caractère. De même, un booléen n'a pas de longueur. Si elles ne sont pas employées dans le contexte prévu, nos fonctions peuvent générer toutes sortes de problèmes et d'erreurs.

Spécifications fonctionnelles

Il est possible et souhaitable de définir précisément les conditions d'emploi de nos fonctions. Ces conditions peuvent concerner les entrées et les sorties de nos fonctions.

Préconditions et postconditions

Les préconditions correspondent aux prérequis d'emploi d'une fonction. Corollairement, les postconditions concernent ce qui est attendu des résultats retournés par une fonction.

bannière exemple

Exemple

Pour notre fonction bonjour() nous pouvons définir des préconditions selon lesquelles les paramètres doivent être de type chaine de caractères et non vides.

Nous pouvons intégrer des vérifications de nos spécifications dans le corps de notre fonction de différentes manières. L'emploi d'assertions peut nous aider dans ce contexte.

Assertions

Le mot clé « assert » du langage Python nous permet de tester si une condition est vraie et de générer une erreur dans le cas contraire.

def bonjour(nom='visiteur', langue='français'):

assert isinstance(nom, str)

assert isinstance(langue, str)

assert len(nom) > 0 and len(langue) > 0

# le reste du code est inchangé

if langue == 'français':

message = 'Bienvenue '

elif langue == 'anglais':

message = 'Hello '

elif langue == 'italien':

message = 'Ciao '

else:

message = 'Saluton '

message = message + nom

return message

Vous pourrez constater le déclenchement d'une erreur d'assertion « AssertionError » si vous appelez la fonction des arguments autres que des chaînes de caractères, ou si une chaîne de caractères vide est passée en argument pour l’un ou l’autre des deux paramètres.

Nous pourrions de la même manière évaluer des postconditions s’assurant que le message est de longueur non nulle et qu’il contient bien le nom du visiteur quand il est spécifié.

Documentation des fonctions

bannière à retenir

À retenir

Il est possible et souhaitable de documenter ses fonctions. Cela consiste à inclure dans la définition de la fonction une chaîne de caractères qui présente synthétiquement la fonction, ses paramètres et les résultats qu'elle produit en retour.

Cette chaîne de caractères, appelée « docstring » en anglais, se présente sous la forme d'une chaîne de caractères multilignes entourée de guillemets triplés. Cette docstring est placée immédiatement après la ligne de définition de la fonction.

def bonjour(nom='visiteur', langue='français'):

"""Retourne un message de bienvenue destiné à un visiteur.

Le visiteur est salué par son nom s'il est précisé.

Le message de bienvenue est rédigé dans la langue choisie (et par défaut en français).

"""

# le reste du code est inchangé

if langue == 'français':

message = 'Bienvenue '

elif langue == 'anglais':

message = 'Hello '

elif langue == 'italien':

message = 'Ciao '

else:

message = 'Saluton '

message = message + nom

return message

Ainsi placée, notre docstring permet à Python d'afficher avec help le message d'aide de notre fonction exactement comme pour les fonctions natives du langage. Ainsi, à la console, en tapant : help(bonjour), on obtient :

help(bonjour)

# produit l'affichage suivant :

Help on function bonjour in module main:

bonjour(nom='visiteur', langue='français')

Retourne un message de bienvenue destiné à un visiteur.

Le visiteur est salué par son nom s'il est précisé.

Le message de bienvenue est rédigé dans la langue choisie (et par défaut en français).

Les spécifications et la documentation des fonctions contribuent à produire un code informatique de qualité. On s'appuiera également sur l'emploi de jeux de tests qui font l'objet d'un cours séparé.

Pour faciliter leur réemploi, les fonctions peuvent être regroupées sous forme de bibliothèques spécialisées.

Bibliothèques

Les bibliothèques sont des conteneurs permettant d'étendre les fonctionnalités initiales du langage, en apportant des outils supplémentaires en fonction des besoins.

Importation d'une bibliothèque

Le langage Python inclut en standard, un grand nombre de modules spécialisés qui composent sa bibliothèque standard.

  • En langage informatique, une bibliothèque est un ensemble de modules, c’est-à-dire un fichier de code, étant regroupées et mises à disposition, afin de ne pas les réécrire à chaque fois.

L'importation d'un tel module s'effectue avec l'instruction « import ». Cette opération ouvre l'accès aux éléments contenus dans ce module.

bannière exemple

Exemple

Le module nommé csv est une bibliothèque dédiée aux traitements des fichiers au format ouvert csv, dont les données tabulaires sont séparées par des virgules ou des points-virgules.

Son importation s'effectue avec l'instruction "import".

import csv

Si la bibliothèque souhaitée ne fait pas partie de la bibliothèque standard de Python, elle devra être installée séparément. Il sera ensuite possible de l'importer comme n'importe quelle autre bibliothèque.

Accès à la documentation d'une bibliothèque

Il est essentiel de savoir utiliser la documentation des bibliothèques pour pouvoir mettre en œuvre correctement les fonctions et d’autres éléments qu'elles peuvent contenir.

La documentation officielle disponible en ligne présente le contenu des différents modules et le fonctionnement des éléments de ces modules.

bannière exemple

Exemple

L'aide du module csv est disponible en ligne en français à l'adresse suivante : https://docs.python.org/fr/3/library/csv.html

Une aide hors ligne est également disponible directement sur votre machine avec la fonction native help(). Cette fonction affiche une aide complète sur le module importé :

help(csv)

# produit l'affichage suivant (tronqué car produit une aide de plus de 400 lignes)

Help on module csv:

NAME

csv - CSV parsing and writing.

MODULE REFERENCE

https://docs.python.org/3.5/library/csv

The following documentation is automatically generated from the Python

source files.

Cette documentation est générée à partir des « docstrings » que nous avons appris à définir pour nos propres fonctions. On comprend tout l'intérêt de bien documenter les fonctions, en particulier quand elles ont vocation à être utilisées par des tiers.

Il est possible d'obtenir de l'aide sur un élément en particulier.

help(csv.reader)

# produit l'affichage suivant :

Help on built-in function reader in module _csv:

reader(…)

csv_reader = reader(iterable [, dialect='excel']

[optional keyword args])

for row in csv_reader:

process(row)

The "iterable" argument can be any object that returns a line of input for each iteration, such as a file object or a list. The optional "dialect" parameter is discussed below. The function also accepts optional keywor arguments which override settings provided by the dialect.

The returned object is an iterator. Each iteration returns a row of the CSV file (which can span multiple input lines).

Pour une vue synthétique sur un module il est possible de faire appel à la fonction native dir() qui retourne la liste de toutes les fonctions du module.

dir(csv)

# produit l'affichage suivant :

['Dialect',

'DictReader',

'DictWriter',

'Error',

'QUOTE_ALL',

'QUOTE_MINIMAL',

'QUOTE_NONE',

'QUOTE_NONNUMERIC',

'Sniffer',

'StringIO',

'_Dialect',

'__all__',

'__builtins__',

'__cached__',

'__doc__',

'__file__',

'__loader__',

'__name__',

'__package__',

'__spec__',

'__version__',

'excel',

'excel_tab',

'field_size_limit',

'get_dialect',

'list_dialects',

're',

'reader',

'register_dialect',

'unix_dialect',

'unregister_dialect',

'writer']

Consulter la documentation des bibliothèques doit devenir un réflexe. Les informations ainsi accessibles facilitent et fiabilisent grandement leur emploi.

Conclusion :

Les fonctions sont de puissants outils à la disposition des programmeurs. Les langages informatiques proposent un nombre important de fonctions natives. Il est possible d’y adjoindre celles issues de bibliothèques spécialisées que nous pouvons importer et sur lesquelles nous savons nous documenter. Nous avons également appris à développer et à paramétrer nos propres fonctions selon nos spécifications, et à documenter nos fonctions.