= Les modules en Python = Que se passe-t-il quand on écrit : {{{#!highlight python from math import * }}} ou bien {{{#!highlight python from math import cos, sin, pi }}} ou {{{#!highlight python from math import cos as cosinus }}} ou encore {{{#!highlight python import math }}} ou {{{#!highlight python 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 {{{#!highlight python from math import sin, pi }}} on obtient les objets appelés `sin` et `pi` dans le module `math`. Avec {{{#!highlight python from math import cos as cosinus }}} on obtient l’objet `cos`, auquel on donne le nom `cosinus`. Avec {{{#!highlight python 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 {{{#!highlight python import math }}} ou {{{#!highlight python 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: {{{#!highlight python import math print(math) type(math) help(math) 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 : {{{#!highlight python import math as m if m.cos(m.pi/4) == m.sin(m.pi/4): 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: {{{#!highlight python def celsius_vers_fahrenheit(d): # convertit des degrés Celsius en Fahrenheit return 9*d/5+32 def fahrenheit_vers_celsius(f): # convertit des degrés Fahrenheit en Celsius return (f-32)*5/9 }}} Ensuite, créez '''''dans le même dossier''''' un nouveau programme, disons, `interface_inutile.py` avec: {{{#!highlight python from temperatures import fahrenheit_vers_celsius as fc entrée=input("Donnez-moi une température en degrés Fahrenheit : ") 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: * aux modules fournis par l’installation de Python; * et éventuellement à des modules qu’on place dans le dossier dans lequel on travaille. == É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 : {{{#!highlight python def celsius_vers_fahrenheit(d): # convertit des degrés Celsius en Fahrenheit return 9*d/5+32 def fahrenheit_vers_celsius(f): # convertit des degrés Fahrenheit en Celsius return (f-32)*5/9 entrée=input("Donnez-moi une température en degrés Fahrenheit : ") print("Voilà la température en degrés Celsius :", fahrenheit_vers_celsius(float(entrée))) }}} Mais alors, chaque fois qu’on fait {{{#!highlight python 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 : {{{#!highlight python def celsius_vers_fahrenheit(d): # convertit des degrés Celsius en Fahrenheit return 9*d/5+32 def fahrenheit_vers_celsius(f): # convertit des degrés Fahrenheit en Celsius return (f-32)*5/9 if __name__ == '__main__': entrée=input("Donnez-moi une température en degrés Fahrenheit : ") 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: {{{#!highlight python import math help(math.cos) 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: {{{#!highlight python def celsius_vers_fahrenheit(c): "Convertit en Fahrenheit une température `d` donnée en Celsius" return 9*c/5+32 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`: {{{#!highlight python """Module de conversion de températures. Fournit des fonctions pour convertir des températures d’une échelle vers une autre. """ def celsius_vers_fahrenheit(c): "Convertit en Fahrenheit une température `d` donnée en Celsius" return 9*c/5+32 def fahrenheit_vers_celsius(f): "Convertit en Celsius une température `f` donnée en Fahrenheit" return (f-32)*5/9 if __name__ == '__main__': entrée=input("Donnez-moi une température en degrés Fahrenheit : ") print("Voilà la température en degrés Celsius :", fahrenheit_vers_celsius(float(entrée))) }}} et testez: {{{#!highlight python import temperatures help(temperatures) }}} == Le module lycee == La distribution [[http://edupython.tuxfamily.org/|EduPython]] est fournie avec un module `lycee`, qu’on peut aussi [[http://download.tuxfamily.org/edupython/lycee.py|télécharger]]. Vous pouvez y jeter un coup d’œil. Si vous n’avez pas Edu``Python 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.