Les modules en Python

Que se passe-t-il quand on écrit :

   1 from math import *

ou bien

   1 from math import cos, sin, pi

ou

   1 from math import cos as cosinus

ou encore

   1 import math

ou

   1 import math as m

?

Dans tous les cas, de nouvelles valeurs deviennent disponibles, sous des noms qu’on contrôle plus ou moins.

Importer des valeurs

Avec

   1 from math import sin, pi

on obtient les objets appelés sin et pi dans le module math.

Avec

   1 from math import cos as cosinus

on obtient l’objet cos, auquel on donne le nom cosinus.

Avec

   1 from math import *

on obtient tous les objets définis dans math, sous leur nom d’origine (difficile de savoir exactement ce qui va être importé: on peut en avoir une idée en regardant la doc, mais ça ne garantit rien).

On a vu tout ça avant.

Importer un module

Avec

   1 import math

ou

   1 import math as m

ce qu’on importe c’est le module math (en lui donnant éventuellement un autre nom). Mais de quoi s’agit-il ?

Testez:

   1 import math
   2 print(math)
   3 type(math)
   4 help(math)
   5 dir(math)

Bref, un module, c’est un objet python comme les autres, qui vient avec des définitions d’objets qui sont accessibles comme des attributs ou des méthodes :

   1 import math as m
   2 if m.cos(m.pi/4) == m.sin(m.pi/4):
   3         print("c’est pas si pourri le calcul en virgule flottante finalement")

Écrire des modules

Un module, ce n’est rien d’autre qu’un programme Python, qu’on importe.

Pour que ça fonctionne, il suffit que ce programme soit écrit dans un fichier, et que l’interpréteur Python sache où le trouver.

Créez un fichier temperatures.py quelque part, contenant par exemple:

   1 def celsius_vers_fahrenheit(d):
   2         # convertit des degrés Celsius en Fahrenheit
   3         return 9*d/5+32
   4 
   5 def fahrenheit_vers_celsius(f):
   6         # convertit des degrés Fahrenheit en Celsius
   7         return (f-32)*5/9

Ensuite, créez dans le même dossier un nouveau programme, disons, interface_inutile.py avec:

   1 from temperatures import fahrenheit_vers_celsius as fc
   2 entrée=input("Donnez-moi une température en degrés Fahrenheit : ")
   3 print("Voilà la température en degrés Celsius :", fc(float(entrée)))

Et voilà !

Notez qu’on ne donne pas le nom complet du fichier, seulement ce qui vient avant .py. Et comme il faut que ce soit un nom valide, on évite bien entendu les espaces et autres caractères problématiques.

Autre point important: on a placé ces deux fichiers dans le même dossier. Pourquoi ? Parce que Python ne peut pas deviner tout seul où aller chercher les modules: par défaut, il va chercher dans une liste de dossiers prédéfinie, stockée dans sys.path.

Essayez d’afficher la valeur de cette variable. Vous pouvez aussi vous amuser à la modifier, pour vérifier qu’on peut ajouter des noms de dossiers à cette liste. Et votre environnement de développement vous permet certainement de le faire de manière un peu plus simple: reste que ce n’est pas une manipulation qu’on souhaite aborder avec des élèves… On s’en tiendra donc:

Écrire des modules correctement

On peut vouloir importer un fichier qu’on a déjà écrit. Si on n’est pas très discipliné, il se peut que ce fichier contienne à la fois des définitions, et puis des tests et instructions diverses.

Typiquement, on aurait pu écrire temperatures.py directement comme :

   1 def celsius_vers_fahrenheit(d):
   2         # convertit des degrés Celsius en Fahrenheit
   3         return 9*d/5+32
   4 
   5 def fahrenheit_vers_celsius(f):
   6         # convertit des degrés Fahrenheit en Celsius
   7         return (f-32)*5/9
   8 
   9 entrée=input("Donnez-moi une température en degrés Fahrenheit : ")
  10 print("Voilà la température en degrés Celsius :", fahrenheit_vers_celsius(float(entrée)))

Mais alors, chaque fois qu’on fait

   1 from temperatures import fahrenheit_vers_celsius as fc

par la suite, le programme se met à nous demander une température :-( Ce n’est pas très réutilisable.

Python permet de gérer ce cas en testant si on est en train d’exécuter le programme principal, ou bien si on est importé par un autre programme. Ça demande un peu de magie noire : il faut tester la valeur de la variable __name__. Ça devient :

   1 def celsius_vers_fahrenheit(d):
   2         # convertit des degrés Celsius en Fahrenheit
   3         return 9*d/5+32
   4 
   5 def fahrenheit_vers_celsius(f):
   6         # convertit des degrés Fahrenheit en Celsius
   7         return (f-32)*5/9
   8 
   9 if __name__ == '__main__':
  10         entrée=input("Donnez-moi une température en degrés Fahrenheit : ")
  11         print("Voilà la température en degrés Celsius :", fahrenheit_vers_celsius(float(entrée)))

Documenter son code

Si on écrit un module, c’est pour qu’il soit utilisé. Et s’il est utilisé, il est de bon goût de le documenter. On a déjà mis des commentaires dans nos fonctions (avec #). On peut faire mieux, en utilisant les docstrings.

Chaque objet vient avec une documentation intégrée, dans l’attribut __doc__. C’est ce qui est affiché par la fonction help.

Par exemple, essayez:

   1 import math
   2 help(math.cos)
   3 help(math)

Cette documentation est automatiquement générée si on fournit une docstring: il suffit de faire commencer le code d’une fonction par une expression de type string pour documenter cette fonction.

Par exemple, testez:

   1 def celsius_vers_fahrenheit(c):
   2         "Convertit en Fahrenheit une température `d` donnée en Celsius"
   3         return 9*c/5+32
   4 
   5 help(celsius_vers_fahrenheit)

De même, si on commence le code de notre module par une chaîne, elle servira à documenter le module lui-même. Si cette documentation est longue, il peut être pertinent d’utiliser des chaînes sur plusieurs lignes, qui s’écrivent en triplant les guillemets : la première ligne servira de titre.

Reprenez temperatures.py:

   1 """Module de conversion de températures.
   2 
   3 Fournit des fonctions pour convertir des températures d’une échelle vers une autre.
   4 """
   5 
   6 def celsius_vers_fahrenheit(c):
   7         "Convertit en Fahrenheit une température `d` donnée en Celsius"
   8         return 9*c/5+32
   9 
  10 def fahrenheit_vers_celsius(f):
  11         "Convertit en Celsius une température `f` donnée en Fahrenheit"
  12         return (f-32)*5/9
  13 
  14 if __name__ == '__main__':
  15     entrée=input("Donnez-moi une température en degrés Fahrenheit : ")
  16     print("Voilà la température en degrés Celsius :", fahrenheit_vers_celsius(float(entrée)))

et testez:

   1 import temperatures
   2 help(temperatures)

Le module lycee

La distribution EduPython est fournie avec un module lycee, qu’on peut aussi télécharger.

Vous pouvez y jeter un coup d’œil. Si vous n’avez pas EduPython sous la main, vous pouvez essayer de mettre ce fichier dans votre dossier courant et l’importer directement… et vérifier que ça ne fonctionne pas. En effet, ça dépend de plein d’autres modules, dont tout l’écosystème de calcul scientifique scipy.

Ça vaut quand même le coup de regarder ce qui s’y trouve, pour s’en inspirer.

EnsInfo: Les modules (last edited 2019-01-23 09:46:17 by LionelVaux)