Apprenez à programmer en Python
Last updated on Monday, September 8, 2014
  • 4 semaines
  • Facile

Ce cours est visible gratuitement en ligne.

Paperback available in this course

Ce cours existe en eBook.

Certificate of achievement available at the end this course

Got it!

Pas à pas vers la modularité (2/2)

Nous allons commencer par voir comment mettre nos programmes en boîte… ou plutôt en fichier. Je vais faire d'une pierre deux coups : d'abord, c'est chouette d'avoir son programme dans un fichier modifiable à souhait, surtout qu'on commence à pouvoir faire des programmes assez sympas (même si vous n'en avez peut-être pas l'impression). Ensuite, c'est un prélude nécessaire à la création de modules.

Comme vous allez le voir, nos programmes Python peuvent être mis dans des fichiers pour être exécutés ultérieurement. De ce fait, vous avez déjà pratiquement toutes les clés pour créer un programme Python exécutable. Le même mécanisme est utilisé pour la création de modules. Les modules sont eux aussi des fichiers contenant du code Python.

Enfin, nous verrons à la fin de ce chapitre comment créer des packages pour regrouper nos modules ayant un rapport entre eux.

C'est parti !

Mettre en boîte notre code

Fini, l'interpréteur ?

Je le répète encore, l'interpréteur est véritablement très pratique pour un grand nombre de raisons. Et la meilleure d'entre elles est qu'il propose une manière interactive d'écrire un programme, qui permet de tester le résultat de chaque instruction. Toutefois, l'interpréteur a aussi un défaut : le code que vous saisissez est effacé à la fermeture de la fenêtre. Or, nous commençons à être capables de rédiger des programmes relativement complexes, même si vous ne vous en rendez pas encore compte. Dans ces conditions, devoir réécrire le code entier de son programme à chaque fois qu'on ouvre l'interpréteur de commandes est assez lourd.

La solution ? Mettre notre code dans un fichier que nous pourrons lancer à volonté, comme un véritable programme !

Comme je l'ai dit au début de ce chapitre, il est grand temps que je vous présente cette possibilité. Mais on ne dit pas adieu à l'interpréteur de commandes pour autant. On lui dit juste au revoir pour cette fois… on le retrouvera bien assez tôt, la possibilité de tester le code à la volée est vraiment un atout pour apprendre le langage.

Emprisonnons notre programme dans un fichier

Pour cette démonstration, je reprendrai le code optimisé du programme calculant si une année est bissextile. C'est un petit programme dont l'utilité est certes discutable mais il remplit un but précis, en l'occurrence dire si l'année saisie par l'utilisateur est bissextile ou non : cela suffit pour un premier essai.

Je vous remets le code ici pour que nous travaillions tous sur les mêmes lignes, même si votre version fonctionnera également sans problème dans un fichier, si elle tournait sous l'interpréteur de commandes.

# Programme testant si une année, saisie par l'utilisateur, est bissextile ou non

annee = input("Saisissez une année : ") # On attend que l'utilisateur fournisse l'année qu'il désire tester
annee = int(annee) # Risque d'erreur si l'utilisateur n'a pas saisi un nombre

if annee % 400 == 0 or (annee % 4 == 0 and annee % 100 != 0):
    print("L'année saisie est bissextile.")
else:
    print("L'année saisie n'est pas bissextile.")

C'est à votre tour de travailler maintenant, je vais vous donner des pistes mais je ne vais pas me mettre à votre place, chacun prend ses habitudes en fonction de ses préférences.

Ouvrez un éditeur basique : sous Windows, le bloc-notes est candidat, Wordpad ou Word sont exclus ; sous Linux, vous pouvez utiliser Vim ou Emacs. Insérez le code dans ce fichier et enregistrez-le avec l'extension .py (exemple bissextile.py), comme à la figure suivante. Cela permettra au système d'exploitation de savoir qu'il doit utiliser Python pour exécuter ce programme (cela est nécessaire sous Windows uniquement).

Enregistrer un fichier Python sous Windows

Sous Linux, vous devrez ajouter dans votre fichier une ligne, tout au début, spécifiant le chemin de l'interpréteur Python (si vous avez déjà rédigé des scripts, en bash par exemple, cette méthode ne vous surprendra pas). La première ligne de votre programme sera :

#!chemin

Remplacez alors le terme chemin par le chemin donnant accès à l'interpréteur, par exemple : /usr/bin/python3.4. Vous devrez changer le droit d'exécution du fichier avant de l'exécuter comme un script.

Sous Windows, rendez-vous dans le dossier où vous avez enregistré votre fichier .py. Vous pouvez faire un double-clic dessus, Windows saura qu'il doit appeler Python grâce à l'extension .py et Python reprend la main. Attendez toutefois car il reste quelques petites choses à régler avant de pouvoir exécuter votre programme.

Quelques ajustements

Quand on exécute un programme directement dans un fichier et que le programme contient des accents (et c'est le cas ici), il est nécessaire de préciser à Python l'encodage de ces accents. Je ne vais pas rentrer dans les détails, je vais simplement vous donner une ligne de code qu'il faudra placer tout en haut de votre programme (sous Linux, cette ligne doit figurer juste en-dessous du chemin de l'interpréteur Python).

# -*-coding:ENCODAGE -*

Sous Windows, vous devrez probablement remplacer ENCODAGE par « Latin-1 ». Sous Linux, ce sera plus vraissemblablement « utf-8 ». Ce n'est pas le lieu, ni le moment, pour un cours sur les encodages. Utilisez simplement la ligne qui marche chez vous et tout ira bien.

Il est probable, si vous exécutez votre application d'un double-clic, que votre programme se referme immédiatement après vous avoir demandé l'année. En réalité, il fait bel et bien le calcul mais il arrive à la fin du programme en une fraction de seconde et referme l'application, puisqu'elle est finie. Pour pallier cette difficulté, il faut demander à votre programme de se mettre en pause à la fin de son exécution. Vous devrez rajouter une instruction un peu spéciale, un appel système qui marche sous Windows (pas sous Linux). Il faut tout d'abord importer le module os. Ensuite, on rajoute l'appel à la fonction os.system en lui passant en paramètre la chaîne de caractères « pause » (cela, à la fin de votre programme). Sous Linux, vous pouvez simplement exécuter votre programme dans la console ou, si vous tenez à faire une pause, utilisez par exemple input avant la fin de votre programme (pas bien élégant toutefois).

# -*-coding:Latin-1 -*

import os # On importe le module os qui dispose de variables 
          # et de fonctions utiles pour dialoguer avec votre 
          # système d'exploitation

# Programme testant si une année, saisie par l'utilisateur, est bissextile ou non

annee = input("Saisissez une année : ") # On attend que l'utilisateur fournisse l'année qu'il désire tester
annee = int(annee) # Risque d'erreur si l'utilisateur n'a pas saisi un nombre

if annee % 400 == 0 or (annee % 4 == 0 and annee % 100 != 0):
    print("L'année saisie est bissextile.")
else:
    print("L'année saisie n'est pas bissextile.")

# On met le programme en pause pour éviter qu'il ne se referme (Windows)
os.system("pause")

Vous pouvez désormais ouvrir votre fichier bissextile.py, le programme devrait fonctionner parfaitement (figure suivante).

Notre programme ne se ferme plus !

Sachez qu'il existe des éditeurs spécialisés pour Python, notamment Idle qui est installé en même temps que Python (personnellement je ne l'utilise pas). Vous pouvez l'ouvrir avec un clic droit sur votre fichier .py et regarder comment il fonctionne, ce n'est pas bien compliqué et vous pouvez même exécuter votre programme depuis ce logiciel. Mais, étant donné que je ne l'utilise pas, je ne vous ferai pas un cours dessus. Si vous avez du mal à utiliser une des fonctionnalités du logiciel, recherchez sur Internet : d'autres tutoriels doivent exister, en anglais dans le pire des cas.

Je viens pour conquérir le monde… et créer mes propres modules

Mes modules à moi

Bon, nous avons vu le plus dur… ça va ? Rassurez-vous, nous n'allons rien faire de compliqué dans cette dernière section. Le plus dur est derrière nous.

Commencez par vous créer un espace de test pour les petits programmes Python que nous allons être amenés à créer, un joli dossier à l'écart de vos photos et musiques. Nous allons créer deux fichiers .py dans ce dossier :

  • un fichier multipli.py, qui contiendra la fonction table que nous avons codée au chapitre précédent ;

  • un fichier test.py, qui contiendra le test d'exécution de notre module.

Vous devriez vous en tirer sans problème. N'oubliez pas de spécifier la ligne précisant l'encodage en tête de vos deux fichiers. Maintenant, voyons le code du fichier multipli.py.

"""module multipli contenant la fonction table"""

def table(nb, max=10):
    """Fonction affichant la table de multiplication par nb de
    1 * nb jusqu'à max * nb"""
    i = 0
    while i < max:
        print(i + 1, "*", nb, "=", (i + 1) * nb)
        i += 1

On se contente de définir une seule fonction, table, qui affiche la table de multiplication choisie. Rien de nouveau jusqu'ici. Si vous vous souvenez des docstrings, dont nous avons parlé au chapitre précédent, vous voyez que nous en avons inséré une nouvelle ici, non pas pour commenter une fonction mais bien un module entier. C'est une bonne habitude à prendre quand nos projets deviennent importants.

Voici le code du fichier test.py, n'oubliez pas la ligne précisant votre encodage, en tête du fichier.

import os
from multipli import *

# test de la fonction table
table(3, 20)
os.system("pause")

En le lançant directement, voilà ce qu'on obtient :

1 * 3 = 3
2 * 3 = 6
3 * 3 = 9
4 * 3 = 12
5 * 3 = 15
6 * 3 = 18
7 * 3 = 21
8 * 3 = 24
9 * 3 = 27
10 * 3 = 30
11 * 3 = 33
12 * 3 = 36
13 * 3 = 39
14 * 3 = 42
15 * 3 = 45
16 * 3 = 48
17 * 3 = 51
18 * 3 = 54
19 * 3 = 57
20 * 3 = 60
Appuyez sur une touche pour continuer...

Je ne pense pas avoir grand chose à ajouter. Nous avons vu comment créer un module, il suffit de le mettre dans un fichier. On peut alors l'importer depuis un autre fichier contenu dans le même répertoire en précisant le nom du fichier (sans l'extension .py). Notre code, encore une fois, n'est pas très utile mais vous pouvez le modifier pour le rendre plus intéressant, vous en avez parfaitement les compétences à présent.

Au moment d'importer votre module, Python va lire (ou créer si il n'existe pas) un fichier .pyc. À partir de la version 3.2, ce fichier se trouve dans un dossier __pycache__.

Ce fichier est généré par Python et contient le code compilé (ou presque) de votre module. Il ne s'agit pas réellement de langage machine mais d'un format que Python décode un peu plus vite que le code que vous pouvez écrire. Python se charge lui-même de générer ce fichier et vous n'avez pas vraiment besoin de vous en soucier quand vous codez, simplement ne soyez pas surpris.

Faire un test de module dans le module-même

Dans l'exemple que nous venons de voir, nous avons créé deux fichiers, le premier contenant un module, le second testant ledit module. Mais on peut très facilement tester le code d'un module dans le module même. Cela veut dire que vous pourriez exécuter votre module comme un programme à lui tout seul, un programme qui testerait le module écrit dans le même fichier. Voyons voir cela.

Reprenons le code du module multipli :

"""module multipli contenant la fonction table"""

def table(nb, max=10):
    """Fonction affichant la table de multiplication par nb de
    1 * nb jusqu'à max * nb"""
    i = 0
    while i < max:
        print(i + 1, "*", nb, "=", (i + 1) * nb)
        i += 1

Ce module définit une seule fonction, table, qu'il pourrait être bon de tester. Oui mais… si nous rajoutons juste en dessous une ligne, par exemple table(8), cette ligne sera exécutée lors de l'importation et donc, dans le programme appelant le module. Quand vous ferez import multipli, vous verrez la table de multiplication par 8 s'afficher… hum, il y a mieux.

Heureusement, il y a un moyen très rapide de séparer les éléments du code qui doivent être exécutés lorsqu'on lance le module directement en tant que programme ou lorsqu'on cherche à l'importer. Voici le code de la solution, les explications suivent :

"""module multipli contenant la fonction table"""

import os

def table(nb, max=10):
    """Fonction affichant la table de multiplication par nb de
    1 * nb jusqu'à max * nb"""
    i = 0
    while i < max:
        print(i + 1, "*", nb, "=", (i + 1) * nb)
        i += 1

# test de la fonction table
if __name__ == "__main__":
    table(4)
    os.system("pause")

Voilà. À présent, si vous faites un double-clic directement sur le fichier multipli.py, vous allez voir la table de multiplication par 4. En revanche, si vous l'importez, le code de test ne s'exécutera pas. Tout repose en fait sur la variable __name__, c'est une variable qui existe dès le lancement de l'interpréteur. Si elle vaut __main__, cela veut dire que le fichier appelé est le fichier exécuté. Autrement dit, si __name__ vaut __main__, vous pouvez mettre un code qui sera exécuté si le fichier est lancé directement comme un exécutable.

Prenez le temps de comprendre ce mécanisme, faites des tests si nécessaire, cela pourra vous être utile par la suite.

Les packages

Les modules sont un des moyens de regrouper plusieurs fonctions (et, comme on le verra plus tard, certaines classes également). On peut aller encore au-delà en regroupant des modules dans ce qu'on va appeler des packages.

En théorie

Comme je l'ai dit, un package sert à regrouper plusieurs modules. Cela permet de ranger plus proprement vos modules, classes et fonctions dans des emplacements séparés. Si vous voulez y accéder, vous allez devoir fournir un chemin vers le module que vous visez. De ce fait, les risques de conflits de noms sont moins importants et surtout, tout est bien plus ordonné.

Par exemple, imaginons que vous installiez un jour une bibliothèque tierce pour écrire une interface graphique. En s'installant, la bibliothèque ne va pas créer ses dizaines (voire ses centaines) de modules au même endroit. Ce serait un peu désordonné… surtout quand on pense qu'on peut ranger tout cela d'une façon plus claire : d'un côté, on peut avoir les différents objets graphiques de la fenêtre, de l'autres les différents évènements (clavier, souris,…), ailleurs encore les effets graphiques…

Dans ce cas, on va sûrement se retrouver face à un package portant le nom de la bibliothèque. Dans ce package se trouveront probablement d'autres packages, un nommé evenements, un autre objets, un autre encore effets. Dans chacun de ces packages, on pourra trouver soit d'autres packages, soit des modules et dans chacun de ces modules, des fonctions.

Ouf ! Cela nous fait une hiérarchie assez complexe non ? D'un autre côté, c'est tout l'intérêt. Concrètement, pour utiliser cette bibliothèque, on n'est pas obligé de connaître tous ses packages, modules et fonctions (heureusement d'ailleurs !) mais juste ceux dont on a réellement besoin.

En pratique

En pratique, les packages sont… des répertoires ! Dedans peuvent se trouver d'autres répertoires (d'autres packages) ou des fichiers (des modules).

Exemple de hiérarchie

Pour notre bibliothèque imaginaire, la hiérarchie des répertoires et fichiers ressemblerait à cela :

  • Un répertoire du nom de la bibliothèque contenant :

    • un répertoire evenements contenant :

      • un module clavier ;

      • un module souris ;

    • un répertoire effets contenant différents effets graphiques ;

    • un répertoire objets contenant les différents objets graphiques de notre fenêtre (boutons, zones de texte, barres de menus…).

Importer des packages

Si vous voulez utiliser, dans votre programme, la bibliothèque fictive que nous venons de voir, vous avez plusieurs moyens qui tournent tous autour des mots clés from et import :

import nom_bibliotheque

Cette ligne importe le package contenant la bibliothèque. Pour accéder aux sous-packages, vous utiliserez un point « . » afin de modéliser le chemin menant au module ou à la fonction que vous voulez utiliser :

nom_bibliotheque.evenements # Pointe vers le sous-package evenements
nom_bibliotheque.evenements.clavier # Pointe vers le module clavier

Si vous ne voulez importer qu'un seul module (ou qu'une seule fonction) d'un package, vous utiliserez une syntaxe similaire, assez intuitive :

from nom_bibliotheque.objets import bouton

En fonction des besoins, vous pouvez décider d'importer tout un package, un sous-package, un sous-sous-package… ou bien juste un module ou même une seule fonction. Cela dépendra de vos besoins.

Créer ses propres packages

Si vous voulez créer vos propres packages, commencez par créer, dans le même dossier que votre programme Python, un répertoire portant le nom du package.

Dans ce répertoire, vous pouvez soit :

  • mettre vos modules, vos fichiers à l'extension .py ;

  • créer des sous-packages de la même façon, en créant un répertoire dans votre package.

Le fichier d'initialisation

En Python, vous trouverez souvent le fichier d'initialisation de package __init__.py dans un répertoire destiné à devenir un package. Ce fichier est optionnel depuis la version 3.3 de Python. Vous n'êtes pas obligé de le créer mais vous pouvez y mettre du code d'initialisation pour votre package. Je ne vais pas rentrer dans le détail ici (vous avez déjà beaucoup de choses à retenir), mais sachez que ce code d'initialisation est appelé quand vous importez votre package.

Un dernier exemple

Voici un dernier exemple, que vous pouvez cette fois faire en même temps que moi pour vous assurer que cela fonctionne.

Dans votre répertoire de code, là où vous mettez vos exemples Python, créez un fichier .py que vous appelerez test_package.py.

Créez dans le même répertoire un dossier package. Dedans, créez un fichier fonctions.py dans lequel vous recopierez votre fonction table.

Dans votre fichier test_package.py, si vous voulez importer votre fonction table, vous avez plusieurs solutions :

from package.fonctions import table
table(5) # Appel de la fonction table

# Ou ...
import package.fonctions
fonctions.table(5) # Appel de la fonction table

Voilà. Il reste bien des choses à dire sur les packages mais je crois que vous avez vu l'essentiel. Cette petite explication révélera son importance quand vous aurez à construire des programmes assez volumineux. Évitez de tout mettre dans un seul module sans chercher à hiérarchiser, profitez de cette possibilité offerte par Python.

En résumé

  • On peut écrire les programmes Python dans des fichiers portant l'extension .py.

  • On peut créer des fichiers contenant des modules pour séparer le code.

  • On peut créer des répertoires contenant des packages pour hiérarchiser un programme.

Example of certificate of achievement
Example of certificate of achievement