.. _td1acenoncesession4rst: ================================================ 1A.2 - Modules, fichiers, expressions régulières ================================================ .. only:: html **Links:** :download:`notebook `, :downloadlink:`html `, :download:`python `, :downloadlink:`slides `, :githublink:`GitHub|_doc/notebooks/td1a/td1a_cenonce_session4.ipynb|*` Le langage Python est défini par un ensemble de règle, une grammaire. Seul, il n’est bon qu’à faire des calculs. Les modules sont des collections de fonctionnalités pour interagir avec des capteurs ou des écrans ou pour faire des calculs plus rapides ou plus complexes. .. code:: ipython3 from jyquickhelper import add_notebook_menu add_notebook_menu() .. contents:: :local: Fichiers ~~~~~~~~ Les fichiers permettent deux usages principaux : - récupérer des données d’une exécution du programme à l’autre (lorsque le programme s’arrête, toutes les variables sont perdues) - échanger des informations avec d’autres programmes (Excel par exemple). Le format le plus souvent utilisé est le fichier plat, texte, txt, csv, tsv. C’est un fichier qui contient une information structurée sous forme de matrice, en ligne et colonne car c’est comme que les informations numériques se présentent le plus souvent. Un fichier est une longue séquence de caractères. Il a fallu choisir une convention pour dire que deux ensembles de caractères ne font pas partie de la même colonne ou de la même ligne. La convention la plus répandue est : - ``\t`` : séparateur de colonnes - ``\n`` : séparateur de lignes Le caractère ``\`` indique au langage python que le caractère qui suit fait partie d’un code. Vous trouverez la liste des codes : `String and Bytes literals `__. **Aparté :** aujourd’hui, lire et écrire des fichiers est tellement fréquent qu’il existe des outils qui font ça dans une grande variété de formats. Vous découvrirez cela lors de la `séance 10 `__. Il est utile pourtant de le faire au moins une fois soi-même pour comprendre la logique des outils et pour ne pas être bloqué dans les cas non prévus. Ecrire et lire des fichiers est beaucoup plus long que de jouer avec des variables. Ecrire signifie qu’on enregistre les données sur le disque dur : elles passent du programme au disque dur (elles deviennent permanentes). Elles font le chemin inverse lors de la lecture. Ecriture ^^^^^^^^ Il est important de retenir qu’un fichier texte ne peut recevoir que des chaînes de caractères. .. code:: ipython3 mat = [[1.0, 0.0],[0.0,1.0] ] # matrice de type liste de listes with open ("mat.txt", "w") as f : # création d'un fichier en mode écriture for i in range (0,len (mat)) : # for j in range (0, len (mat [i])) : # s = str (mat [i][j]) # conversion en chaîne de caractères f.write (s + "\t") # f.write ("\n") # # on vérifie que le fichier existe : import os print([ _ for _ in os.listdir(".") if "mat" in _ ] ) # la ligne précédente utilise le symbole _ : c'est une variable # le caractère _ est une lettre comme une autre # on pourrait écrire : # print([ fichier for fichier in os.listdir(".") if "mat" in fichier ] ) # on utilise cette convention pour dire que cette variable n'a pas vocation à rester .. parsed-literal:: ['mat.txt', 'matrix_dictionary.ipynb', 'seance4_excel_mat.txt', 'seance4_excel_mat.xlsx'] Le même programme mais écrit avec une écriture condensée : .. code:: ipython3 mat = [[1.0, 0.0],[0.0,1.0] ] # matrice de type liste de listes with open ("mat.txt", "w") as f : # création d'un fichier s = '\n'.join ( '\t'.join( str(x) for x in row ) for row in mat ) f.write ( s ) # on vérifie que le fichier existe : print([ _ for _ in os.listdir(".") if "mat" in _ ] ) .. parsed-literal:: ['mat.txt', 'matrix_dictionary.ipynb', 'seance4_excel_mat.txt', 'seance4_excel_mat.xlsx'] On regare les premières lignes du fichier ``mat2.txt`` : .. code:: ipython3 import pyensae %load_ext pyensae %head mat.txt .. raw:: html
    1.0	0.0
    0.0	1.0
    
Lecture ^^^^^^^ .. code:: ipython3 with open ("mat.txt", "r") as f : # ouverture d'un fichier mat = [ row.strip(' \n').split('\t') for row in f.readlines() ] print(mat) .. parsed-literal:: [['1.0', '0.0'], ['0.0', '1.0']] On retrouve les mêmes informations à ceci près qu’il ne faut pas oublier de convertir les nombres initiaux en ``float``. .. code:: ipython3 with open ("mat.txt", "r") as f : # ouverture d'un fichier mat = [ [ float(x) for x in row.strip(' \n').split('\t') ] for row in f.readlines() ] print(mat) .. parsed-literal:: [[1.0, 0.0], [0.0, 1.0]] Voilà qui est mieux. Le module `os.path `__ propose différentes fonctions pour manipuler les noms de fichiers. Le module `os `__ propose différentes fonctions pour manipuler les fichiers : .. code:: ipython3 import os for f in os.listdir('.'): print (f) .. parsed-literal:: .ipynb_checkpoints data exemple_fichier.txt image.png image.png.gv images integrale_rectangle.ipynb integrale_rectangle_correction.ipynb j2048.ipynb j2048_correction.ipynb mat.txt matrix_dictionary.ipynb monmodule.py monmodule3.py page.html pp_exo_deviner_un_nombre.ipynb pp_exo_deviner_un_nombre_correction.ipynb README.txt seance4_excel.txt seance4_excel.xlsx seance4_excel_mat.txt seance4_excel_mat.xlsx td1a_cenonce_session1.ipynb td1a_cenonce_session2.ipynb td1a_cenonce_session3.ipynb td1a_cenonce_session4.ipynb td1a_cenonce_session5.ipynb td1a_cenonce_session6.ipynb td1a_correction_session1.ipynb td1a_correction_session2.ipynb td1a_correction_session3.ipynb td1a_correction_session4.ipynb td1a_correction_session5.ipynb td1a_correction_session6.ipynb td1a_pyramide_bigarree.ipynb td1a_pyramide_bigarree_correction.ipynb td2_1.png texte_langue.ipynb texte_langue_correction.ipynb voeux.zip VOEUX01.txt VOEUX05.txt VOEUX06.txt VOEUX07.txt VOEUX08.txt VOEUX09.txt VOEUX74.txt VOEUX75.txt VOEUX79.txt VOEUX83.txt VOEUX87.txt VOEUX89.txt VOEUX90.txt VOEUX94.txt __pycache__ with ^^^^ De façon pragmatique, l’instruction `with `__ permet d’écrire un code plus court d’une instruction : ``close``. Les deux bouts de code suivant sont équivalents : .. code:: ipython3 with open("exemple_fichier.txt", "w") as f: f.write("something") .. code:: ipython3 f = open("exemple_fichier.txt", "w") f.write("something") f.close() L’instruction ``close`` *ferme* le fichier. A l’ouverture, le fichier est réservé par le programme Python, aucune autre application ne peut écrire dans le même fichier. Après l’instruction ``close``, une autre application pour le supprimer, le modifier. Avec le mot clé ``with``, la méthode ``close`` est implicitement appelée. à quoi ça sert ? ^^^^^^^^^^^^^^^^ On écrit très rarement un fichier texte. Ce format est le seul reconnu par toutes les applications. Tous les logiciels, tous les langages proposent des fonctionnalités qui exportent les données dans un format texte. Dans certaines circonstances, les outils standards ne fonctionnent pas - trop grops volumes de données, problème d’encoding, caractère inattendu -. Il faut se débrouiller. Exercice 1 : Excel :math:`\rightarrow` Python :math:`\rightarrow` Excel ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Il faut télécharger le fichier `seance4_excel.xlsx `__ qui contient une table de trois colonnes. Il faut : - enregistrer le fichier au format texte, - le lire sous python - créer une matrice carrée 3x3 où chaque valeur est dans sa case (X,Y), - enregistrer le résultat sous format texte, - le récupérer sous Excel. Autres formats de fichiers ~~~~~~~~~~~~~~~~~~~~~~~~~~ Les fichiers texte sont les plus simples à manipuler mais il existe d’autres formats classiques~: - `html `__ : les pages web - `xml `__ : données structurées - [zip](http://fr.wikipedia.org/wiki/ZIP_(format_de_fichier), `gz `__ : données compressées - `wav `__, `mp3 `__, `ogg `__ : musique - `mp4 `__, `Vorbis `__ : vidéo - … Modules ~~~~~~~ Les modules sont des extensions du langages. Python ne sait quasiment rien faire seul mais il bénéficie de nombreuses extensions. On distingue souvent les extensions présentes lors de l’installation du langage (le module `math `__) des extensions externes qu’il faut soi-même installer (`numpy `__). Deux liens : - `modules officiels `__ - `modules externes `__ Le premier réflexe est toujours de regarder si un module ne pourrait pas vous être utile avant de commencer à programmer. Pour utiliser une fonction d’un module, on utilise l’une des syntaxes suivantes : .. code:: ipython3 import math print (math.cos(1)) from math import cos print (cos(1)) from math import * # cette syntaxe est déconseillée car il est possible qu'une fonction print (cos(1)) # porte le même nom qu'une des vôtres .. parsed-literal:: 0.5403023058681398 0.5403023058681398 0.5403023058681398 Exercice 2 : trouver un module (1) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Aller à la page `modules officiels `__ (ou utiliser un moteur de recherche) pour trouver un module permettant de générer des nombres aléatoires. Créer une liste de nombres aléatoires selon une loi uniforme puis faire une permutation aléatoire de cette séquence. Exercice 3 : trouver un module (2) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Trouver un module qui vous permette de calculer la différence entre deux dates puis déterminer le jour de la semaine où vous êtes nés. Module qu’on crée soi-même ~~~~~~~~~~~~~~~~~~~~~~~~~~ Il est possible de répartir son programme en plusieurs fichiers. Par exemple, un premier fichier ``monmodule.py`` qui contient une fonction : .. code:: ipython3 # fichier monmodule.py import math def fonction_cos_sequence(seq) : return [ math.cos(x) for x in seq ] if __name__ == "__main__" : print ("ce message n'apparaît que si ce programme est le point d'entrée") .. parsed-literal:: ce message n'apparaît que si ce programme est le point d'entrée La cellule suivante vous permet d’enregistrer le contenu de la cellule précédente dans un fichier appelée ``monmodule.py``. .. code:: ipython3 code = """ # -*- coding: utf-8 -*- import math def fonction_cos_sequence(seq) : return [ math.cos(x) for x in seq ] if __name__ == "__main__" : print ("ce message n'apparaît que si ce programme est le point d'entrée") """ with open("monmodule.py", "w", encoding="utf8") as f : f.write(code) Le second fichier : .. code:: ipython3 import monmodule print ( monmodule.fonction_cos_sequence ( [ 1, 2, 3 ] ) ) .. parsed-literal:: [0.5403023058681398, -0.4161468365471424, -0.9899924966004454] **Note :** Si le fichier ``monmodule.py`` est modifié, *python* ne recharge pas automatiquement le module si celui-ci a déjà été chargé. On peut voir la liste des modules en mémoire dans la variable ``sys.modules`` : .. code:: ipython3 import sys list(sorted(sys.modules))[:10] .. parsed-literal:: ['IPython', 'IPython.core', 'IPython.core.alias', 'IPython.core.application', 'IPython.core.async_helpers', 'IPython.core.autocall', 'IPython.core.builtin_trap', 'IPython.core.compilerop', 'IPython.core.completer', 'IPython.core.completerlib'] Pour retirer le module de la mémoire, il faut l’enlever de ``sys.modules`` avec l’instruction ``del sys.modules['monmodule']``. *Python* aura l’impression que le module *monmodule.py* est nouveau et il l’importera à nouveau. Exercice 4 : son propre module ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Que se passe-t-il si vous remplacez ``if __name__ == "__main__":`` par ``if True :``, ce qui équivaut à retirer la ligne ``if __name__ == "__main__":`` ? Expressions régulières ~~~~~~~~~~~~~~~~~~~~~~ Pour la suite de la séance, on utilise comme préambule les instructions suivantes : .. code:: ipython3 import pyensae.datasource discours = pyensae.datasource.download_data('voeux.zip', website = 'xd') La documentation pour les expressions régulières est ici : `regular expressions `__. Elles permettent de rechercher des motifs dans un texte : - *4 chiffres / 2 chiffres / 2 chiffres* correspond au motif des dates, avec une expression régulière, il s’écrit : ``[0-9]{4}/[0-9]{2}/[0-9]{2}`` - *la lettre a répété entre 2 et 10 fois* est un autre motif, il s’écrit : ``a{2,10}``. .. code:: ipython3 import re # les expressions régulières sont accessibles via le module re expression = re.compile("[0-9]{2}/[0-9]{2}/[0-9]{4}") texte = """Je suis né le 28/12/1903 et je suis mort le 08/02/1957. Ma seconde femme est morte le 10/11/63.""" cherche = expression.findall(texte) print(cherche) .. parsed-literal:: ['28/12/1903', '08/02/1957'] Pourquoi la troisième date n’apparaît pas dans la liste de résultats ? Exercice 5 : chercher un motif dans un texte ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ On souhaite obtenir toutes les séquences de lettres commençant par *je* ? Quel est le motif correspondant ? Il ne reste plus qu’à terminer le programme précédent. Exercice 6 : chercher un autre motif dans un texte ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Avec la même expression régulière, rechercher indifféremment le mot *securite* ou *insecurite*. On peut passer du temps à construire des expressions assez complexes surtout quand on oublie quelques `Petites subtilités avec les expressions régulières en Python `__. Exercice 7 : recherche les urls dans une page wikipédia ------------------------------------------------------- On pourra prendre comme exemple la page du programme `Python `__. Exercice 8 : construire un texte à motif ---------------------------------------- A l’inverse des expressions régulières, des modules comme `Mako `__ ou `Jinja2 `__ permettent de construire simplement des documents qui suivent des règles. Ces outils sont très utilisés pour la construction de page web. On appelle cela faire du `templating `__. Créer une page web qui affiche à l’aide d’un des modules la liste des dimanches de cette année.