Modules ======= Définition et importation ------------------------- Un module est un ensemble de définitions d'objets placé dans un fichier (d'extension :py:obj:`py`). Supposons que l'on souhaite écrire un module pour définir des fonctions permettant de faire des calculs sur le rayonnement du corps noir. Pour ce faire, on enregistre dans un fichier nommé ``corpsnoir.py`` le code suivant : .. code-block:: python :linenos: import numpy h=6.626e-34 # constante de Planck c=299792458.0 # vitesse de la lumière k=1.38e-23 # constante de Boltzmann def exitance(L,T): # L : longueur d'onde en micromètres # T : température en Kelvin L = L*1e-6 return 2*numpy.pi*h*c**2/(L**5*(numpy.exp(h*c/(L*k*T))-1))*1e-6 Ce module comporte trois définitions d'objets de type :py:obj:`float` et une définition de fonction, avec bien sûr des noms associés. Un module doit être importé dans le script où on veut l'utiliser, ou bien depuis la console. L'importation se fait par l'instruction suivante : >>> import corpsnoir Il faut que l'interpréteur de Python trouve le fichier. Il effectue sa recherche dans une liste de chemins, consultable par : >>> import sys >>> sys.path Le répertoire de travail est le premier de la liste. Si le fichier se trouve dans le répertoire de travail, il peut donc être importé. On remarque par ailleurs que le module importe lui-même un autre module, nommé :py:obj:`numpy`, qui se trouve dans un répertoire de la distribution Python utilisée. Dès lors que le module est importé, les noms qu'il définit sont accessibles par la syntaxe suivante : >>> corpsnoir.h 6.626e-34 >>> corpsnoir.exitance(500,1000) 0.00040995221937790315 Les noms définis dans le module ne sont pas dans l'espace de noms global, mais sont accessibles via la notation :py:obj:`corpsnoir.` (le nom du module suivi d'un point). Il y a ainsi séparation entre l'espace des noms courant et l'espace des noms du module, ce qui est une très bonne chose. L'inconvénient est l'obligation de placer le nom du module en préfixe de chaque nom. La tâche peut être allégée en introduisant un *alias*, c'est-à-dire un nom abrégé qui vient remplacer le nom complet, par exemple : >>> import corpsnoir as cn >>> cn.h 6.626e-34 Il est possible d'importer des noms dans l'espace de noms courant, mais il faut le faire avec prudence, car cet espace de noms peut contenir déjà des noms identiques à certains noms du module, ce qui viendrait détruire les premiers. Il est donc préférable d'importer dans l'espace de noms courant seulement les noms dont on a besoin : >>> from corpsnoir import exitance >>> exitance(500,1000) 0.00040995221937790315 En principe, il vaut mieux éviter ce type d'importation. Il est d'ailleurs possible de faire pire en important dans l'espace de noms courant tous les noms du module : >>> h = 100 >>> from corpsnoir import * >>> h 6.626e-34 Comme on le voit sur cet exemple, le nom ``h`` dont la déclaration précède l'importation du module et qui pointait vers un entier de valeur 100, est remplacé par la variable définie dans le module, ce qui signifie que le même nom fait finalement référence à un flottant de valeur ``6.626e-34``. Pour éviter ce genre de désagrément (dont les conséquences peuvent être désastreuses), il est préférable de ne jamais importer de noms dans l'espace de noms courant. Notons que le contenu d'un module peut être obtenu par la fonction :py:obj:`dir` (le module doit être déjà importé) : >>> dir(corpsnoir) ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'c', 'exitance', 'h', 'k', 'numpy'] Ce module importe lui-même un module, nommé :py:obj:`numpy`, dont il a besoin pour faire ses calculs. Cependant, celui-ci serait accessible par la syntaxe ``corpsnoir.numpy``, qui n'a pas de sens puisque le module numpy ne fait pas partie du module corpsnoir. Exemple : module math --------------------- On appelle bibilothèque (library en anglais) un ensemble de modules, mais la notion de bibliothèque ne correspond à rien de précis en Python. Le logiciel Python est livré avec une bibliothèque appelée **bibliothèque standard**. Cette bibliothèque est donc présente dans toutes les distributions de Python, même les plus petites. La bibliothèque standard comporte des modules qui répondent à des besoins très généraux et très variés. Leur liste, ainsi que leur documentation complète, est consultable sur https://docs.python.org/fr/3/library/index.html Nous nous intéressons en particulier au module :py:obj:`math`, qui comporte des fonctions mathématiques d'usage courant. Voici par exemple comment se servir de ce module pour calculer un cosinus : >>> import math >>> math.pi 3.141592653589793 >>> math.cos(math.pi*0.5) 6.123233995736766e-17 On remarque au passage que le résultat de ce calcul est affecté d'une erreur d'arrondi, puisque le résultat exact est 0. Paquet ------- Un *paquet* (en anglais **package**) est une organisation hiérarchique de plusieurs modules, qui prend la forme d'une arborescence. Supposons que l'on souhaite créer un paquet nommé :py:obj:`thermo` qui contiendrait le module :py:obj:`corpsnoir` et d'autres modules destinés à faire des calculs dans différents domaines de la thermodynamique. Afin de réaliser un paquet dit *classique*, nous devons créer l'arborescence de fichiers suivante :: thermo/ __init__.py corpsnoir __init__.py gazparfait __init__.py fluides __init__.py etc. Chaque sous-dossier constitue un module (en fait un sous-module). Le fichier __init__.py contient le code python qui est exécuté lors de l'importation du module. Dans le cas présent, il faut placer le contenu du fichier :py:obj:`corpsnoir.py` précédent dans le fichier :py:obj:`__init__.py` du dossier :py:obj:`corpsnoir`. L'importation du module se fait de la manière suivante : >>> import thermo.corpsnoir ou bien avec un alias : >>> import thermo.corpsnoir as cn Le fichier :py:obj:`__init__.py` du dossier :py:obj:`thermo` constitue également un module, le module racine du paquet, où on placerait des définitions générales de la thermodynamique, et qui serait importé par : >>> import thermo Cependant, cette dernière importation n'importe pas les sous-modules. Ceux-ci doivent être importés explicitement. Les bibliothèques de grande taille sont généralement organisées sous forme de paquets. Les bibliothèques les plus importantes pour le calcul numérique sont :py:obj:`numpy`, :py:obj:`matplolib` et :py:obj:`scipy`. On peut par exemple importer :py:obj:`numpy` : >>> import numpy Ce module apporte les fonctions de base pour créer et manipuler des tableaux numériques. Si l'on souhaite en plus générer des tableaux contenant des nombres aléatoires, il faudra faire l'importation suivante : >>> import numpy.random