Les fonctions
Objectifs de la section
2-5 Fonctions
2-6 Conventions du langage de programmation utilisé
Temps requis
20 minutes
Comme vu précédemment, les fonctions (appelées sous-programme dans le livre) permettent d'effectuer certaines manipulations plus complexes, en séparant le code en plus petite unité. Les grandes forces des fonctions sont qu'elles permettent de :
- Séparer le code en plus petites unités, ce qui augmente la lisibilité et facilite le débogage;
- Réutiliser le même traitement en appelant la fonction à plusieurs endroit, ce qui diminue l'effort de développement et réduit les erreurs;
- Encapsuler des traitements pour qu'ils n'aient pas d'effet sur le reste du programme, ce qui réduit les erreurs et augmente la flexibilité et la modularité du code (le code ressemble à des blocs lego que l'on assemble).
Définir une fonction
Section 3.3 / 3.4
Pour définir une fonction, on utilise la syntaxe suivante (noter que ce qui est entre < > est remplacé par un identificateur).
Syntaxe d'une fonction | |
---|---|
Signature
La ligne débutante par def
est appelée signature de la fonction. C'est la seule chose qu'il faut connaître pour utiliser la fonction.
Ajouter des paramètres
La fonction additionner
ci-dessous n'est pas très intéressante : elle additionne toujours les mêmes deux nombres ! Une fonction plus utile serait une fonction qui additionne deux nombres quelconques. On doit dans ce cas-là permettre à la fonction de s'exécuter sur diverses valeurs. C'est ce que nous ferons avec les paramètres : ils permettent de transmettre une ou plusieurs valeurs à la fonction. Pour déclarer qu'une fonction accepte des paramètres, on doit les déclarer dans la signature de la fonction, entre les parenthèses.
Syntaxe d'une fonction avec des paramètres | |
---|---|
Dans l'exemple ci-dessous, le paramètre operande1
prend la valeur 1, lors de son exécution, car le chiffre 1 est passé à la position du paramètre operande1
. On peut aussi utiliser des variables; dans ce cas, la valeur de la variable est utilisée.
Syntaxe d'une fonction avec des paramètres | |
---|---|
Les paramètres fonctionnent en tout point comme des variables, sauf que si on les modifie, la nouvelle valeur ne se transmet pas hors de la fonction, comme illustré dans la section sur la portée des variables.
Retourner une valeur
La fonction additionner
, bien que plus modulaire n'est pas encore très utile, car on ne peut rien faire avec le résultat de l'opération d'addition. Il serait plus intéressant de récupérer le résultat de l'opération et de pouvoir le réutiliser dans le reste du programme. C'est que l'on peut faire avec l'instruction return
.
Travailler avec des fonctions
Maintenant que nous avons vu la syntaxe de base des fonctions, nous verrons deux considérations importantes avec les fonctions, soit la portée de variables et la documentation.
La portée des variables
Section 3.5
Chaque variable est visible (accessible) à l'endroit où elle est déclarée. C'est ce que l'on appelle l'espace de visibilité d'une variable. De plus, la règle qui stipule que chaque identificateur doit être unique s'applique uniquement dans un même espace : deux variables peuvent porter le même nom tant qu'elles ne sont pas dans le même espace. On déclare un nouvel espace de visibilité chaque fois que l'on déclare une fonction. Prenons l'exemple du code suivant, la variable valeur
de la fonction
n'est pas la même que celle de l'espace global.
Portée des variables | |
---|---|
Également, les changements aux paramètres ne se propagent pas hors de la fonction.
Propagation des changements | |
---|---|
Utiliser les variables globales
Toutefois, on pourrait quand même faire référence à une variable globale dans une fonction, mais cela comporte de hauts risques d'erreurs difficiles à repérer. En effet, rien ne garantit que la variable globale est dans un état cohérent au moment de l'exécution du code.
Utilisation d'une variable globale - avec succès | |
---|---|
En permuttant les lignes 5 et 6, on obtient plutôt une erreur
Utilisation d'une variable globale - avec erreur | |
---|---|
La règle à respecter est de ne jamais appeler de variables globales dans une fonction : toujours utiliser des paramètres.
Espace de visibilité
Contrairement à plusieurs autres langages de programme, les instructions conditionnelles et les boucles ne déclarent pas de nouvel espace de visibilité.
Documenter ses fonctions
Documenter ses fonctions
En contexte d'évaluation, il y a toujours des points dédiés à la documentation correcte des fonctions. On peut voir cela comme la méthodologie de l'informatique.
On utilise les docstring
pour commenter les fonctions. Une docstring
est encapsulée par 3 guillemets anglais « " ». On place la docstring
directement sous la signature de la fonction. Elle se compose de trois parties :
- La description du but de la fonction. On y explique ce que la fonction fait et non comment elle le fait. Si la description entre sur une ligne, on la place sur la même ligne que les guillemets ouvrants, sinon on commence à la ligne suivante.
- Les paramètres de la fonction qui sont introduits par le mot-clé « Paramètre(s) ». Ils ont le format
nom -- description
. S'il n'y a pas de paramètre, on omet cette partie. - La valeur de retour de la fonction introduite par le mot-clé « Retour ». S'il n'y a pas de valeur de retour, on omet cette partie.
Exemples de docstring | |
---|---|
Exercice
Quels sont les erreurs dans la documentation suivante ?
Solution
Les quatre erreurs sont :
- La description décrit le fonctionnement du code plutôt que d'indiquer son intention
- Une description qui prend plusieurs lignes doit commencer sur la ligne en-dessous des guillemets ouvrants
- Le symbole entre le nom d'une variable et sa description est --
- Il manque la description de la valeur de retour
Structurer un programme
Dans un programme complexe et bien structuré, il y a très peu ou aucun code qui n'est pas dans une fonction. Un programme Python n'est qu'une série de fonctions qui s'appellent entre elles. Pour les programmes plus complexes, on sépare même les fonctions dans plusieurs fichiers, en regroupant les fonctions qui jouent un rôle commun dans un même fichier.
Travailler avec plusieurs fichiers
Un fichier de code Python constitue en fait ... un paquet ! Tant qu'on enregistre les fichiers dans un même répertoire, on peut les importer comme des paquets. Le nom du paquet est simplement le nom du fichier. Par exemple, on code plusieurs fonctions de géométrie (calcul d'aire, d'angle et de périmètre) que l'on enregistre dans un fichier appelé geometrie.py
. Dans un autre programme, on pourrait inclure la ligne import geometrie
pour pouvoir utiliser les fonctions déclarées dans ce fichier.
Enregistrer mon fichier au bon endroit
Pour que l'inclusion fonctionne, il faut que les deux fichiers soient enregistrés au même endroit, sinon l'on doit indiquer le chemin relatif vers le fichier inclus. Pour me déplacer dans un chemin relatif, on utilise les symboles suivants :
/
pour changer de répertoire;..
pour remonter dans un répertoire parent;- le nom du répertoire pour accéder à un répertoire enfant.
Supposons que mon fichier à inclure, geometrie.py soit sauvegardé dans le dossier Reutilisable qui est lui-même dans le dossier Projet Python. On travaille dans le fichier programme.py qui est sauvegardé dans le dossier Exercices qui est lui-même dans le dossier Projet Python. Pour accéder à geometrie.py on devrait utiliser l'expression dans le fichier programme.py :
import ../Reutilisable/geometrie
Le premier ..
permet d'indiquer qu'on se déplace vers le dossier parent de celui qui contient programme.py soit le dossier Projet Python. Ensuite, on se déplace vers le sous-dossier Reutilisable et finalement on indique le fichier à inclure : geometrie.
Protéger ses fichiers contre les exécutions indésirables
Quand on réutilise des fichiers de code (et c'est une bonne pratique à faire en général), on doit protéger nos fichiers des exécutions accidentelles avec une instruction spéciale. Si on ne le fait pas, tout le code global du fichier est exécuté à chaque fois que le fichier est importé ! Ce comportement est source d'erreurs, souvent étranges et difficiles à repérer. Chaque fichier qui contient du code global devrait définir cette instruction qui permet de préciser le point d'entrée du programme.
Cette instruction assure d'exécuter le code global seulement si ce fichier est le point d'entrée de notre programme; s'il est importé dans un autre programme, alors on ne l'exécute pas. C'est reconnu comme une bonne pratique à faire systématiquement.
De plus, on retrouve souvent une seule instruction dans ce bloc : l'appel à la fonction qui gère le programme.
Exemple de fichier pour faire des exercices
Voici un exemple de structure de fichier pour réaliser tous vos exercices d'une même section dans un même fichier ou du moins, plusieurs exercices dans un même fichier. Faites attention de ne pas vous perdre dans votre code !
Regrouper des exercice | |
---|---|
En commentant le bon appel de fonction, cela vous permet de tester un exercice à la fois. De plus, l'encapsulation des fonctions assure que vos variables ne soient pas partagées entre plusieurs exercices, tant que vous utilisez toujours des variables locales.
Exercices
Page 56 et suivantes
Recommandés : 3.1, 3.2, 3.7, 3.14, 3.1, 3.16, 3.17, 3.18, 3.19, 3.21
Page 70 et suivantes
Recommandés : 4.12, 4.15, 4.17