1A.2 - Modules, fichiers, expressions régulières (correction)

Links: notebook, html, PDF, python, slides, GitHub

Correction.

from jyquickhelper import add_notebook_menu
add_notebook_menu()
%matplotlib inline

Exercice 1 : Excel \rightarrow Python \rightarrow Excel

Il faut télécharger le fichier seance4_excel.xlsx puis l’enregistrer au formet **texte (séparateur : tabulation) (.txt)*. On rappelle les étapes de l’exercice :

  • 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.
with open ("seance4_excel.txt", "r") as f :
    mat = [ row.strip(' \n').split('\t') for row in f.readlines() ]

mat = mat [1:]
res = [ [ None ] * 3 for i in range(5) ]
for i,j,v in mat :
    res [ int(j)-1 ] [ int (i)-1 ] = float(v)

with open ("seance4_excel_mat.txt", "w") as f :
    f.write ( '\n'.join ( [   '\t'.join( [ str(x) for x in row ] ) for row in res ] ) )

Il est très rare d’écrire ce genre de code. En règle générale, on se sert de modules déjà existant comme pandas, xlrd et openpyxl. Cela évite la conversion au format texte :

import pandas
df = pandas.read_excel("seance4_excel.xlsx", sheetname="Feuil1")
mat = df.pivot("X", "Y", "value")
mat.to_excel("seance4_excel_mat.xlsx")
mat
c:python370_x64libsite-packagespandasioexcel.py:329: FutureWarning: The sheetname keyword is deprecated, use sheet_name instead
  **kwds)
Y 1 2 3 4 5
X
1 0.0 -1.0 -2.0 -3.0 -4.0
2 1.0 0.0 -1.0 -2.0 -3.0
3 2.0 1.0 0.0 -1.0 NaN

C’est un peu plus rapide.

Exercice 2 : trouver un module (1)

Le module random est celui qu’on cherche.

import random
alea = [ random.random() for i in range(10) ]
print (alea)
random.shuffle(alea)
print (alea)
[0.26765749846551, 0.45519502325940386, 0.16553839057702346, 0.35096250179212973, 0.6022413534014167, 0.7418605210099644, 0.17746584867591964, 0.993544997342843, 0.8987249281875996, 0.22046947181374688]
[0.6022413534014167, 0.45519502325940386, 0.26765749846551, 0.22046947181374688, 0.17746584867591964, 0.16553839057702346, 0.7418605210099644, 0.993544997342843, 0.35096250179212973, 0.8987249281875996]

Exercice 3 : trouver un module (2)

Le module datetime permet de faire des opérations sur les dates.

from datetime import datetime
date1 = datetime(2013,9,9)
date0 = datetime(2013,8,1)
print (date1 - date0)
birth = datetime (1975,8,11)
print (birth.weekday())  # lundi
39 days, 0:00:00
0

Exercice 4 : son propre module

On effectue le remplacement if __name__ == "__main__": par if True : :

# fichier monmodule2.py
import math

def fonction_cos_sequence(seq) :
    return [ math.cos(x) for x in seq ]

if __name__ == "__main__" :
    # et une petite astuce quand on travaille sous notebook
    code = """
        # -*- coding: utf-8 -*-
        import math
        def fonction_cos_sequence(seq) :
            return [ math.cos(x) for x in seq ]
        if True :
            print ("Ce message n'apparaît que si ce programme est le point d'entrée.")
        """.replace("        ","")
    with open("monmodule3.py", "w", encoding="utf8") as f : f.write(code)
import monmodule3
print ( monmodule3.fonction_cos_sequence ( [ 1, 2, 3 ] ) )
Ce message n'apparaît que si ce programme est le point d'entrée.
[0.5403023058681398, -0.4161468365471424, -0.9899924966004454]

Le message ce message n'apparaît que ce programme est le point d'entrée apparaît maintenant alors qu’il n’apparaissait pas avec la version de l’énoncé. Comme il apparaît après *, cela montre que cette ligne est exécutée si le module est importé.

import monmodule3

Si on importe le module une seconde fois, le message n’apparaît plus : le langage Python a détecté que le module avait déjà été importé. Il ne le fait pas une seconde fois.

Exercice 5 : chercher un motif dans un texte

L’expression régulière est je .{1,60}. Le symbol . signifie n’importe quel caractère. Suivi de {1,60} veut dire n’importe quel caractère répété entre 1 et 60 fois.

import pyensae, re
discours = pyensae.download_data('voeux.zip', website = 'xd')

exp = re.compile ("je .{1,60}", re.IGNORECASE)
for fichier in discours :
    print("----",fichier)
    try:
        with open(fichier,"r") as f : text = f.read()
    except:
        with open(fichier,"r", encoding="latin-1") as f : text = f.read()
    je = exp.findall(text)
    for t in je :
            print (t)
---- VOEUX01.txt
je pense aussi à nos compatriotes de Toulouse, mais également d
je veux dire, en ce 31 décembre, la solidarité et l'amitié de l
je sais que vous voulez faire vivre les valeurs qui sont celles
je souhaite une bonne et heureuse année.
---- VOEUX05.txt
je pense d'abord à toutes celles et à tous ceux qui connaissent
Je pense aussi à nos soldats qui sont engagés sur tous les cont
je veux dire à la famille de Bernard PLANCHE, que les pouvoirs
je prendrai rapidement des initiatives pour relancer la constru
---- VOEUX06.txt
je pense d'abord à toutes celles et à tous ceux qui sont victim
Je veux aussi saluer avec respect et reconnaissance nos soldats
je me bats pour qu'elle prenne toute sa place dans ce nouveau m
Je me bats pour que chaque Français, pour que chaque jeune en p
je voudrais que les choses avancent plus vite, et qu'elles avan
je m'y engagerai pleinement. Je voudrais vous dire ce soir quel
Je sais les souffrances et les difficultés auxquelles certains
Je connais vos attentes pour ce qui concerne les salaires et le
je demande au Gouvernement d'avancer sur ce point dans les tout
---- VOEUX07.txt
je m'adresse à vous.
Je pense à vous qui vous préparez à fêter la nouvelle année ave
Je pense à vous qui êtes obligés de travailler cette nuit au se
Je pense aussi à vous qui êtes seuls et pour qui cette soirée s
Je pense à vous, que la vie a éprouvés, et que la tristesse ou
je veux adresser un message d'espérance, un message de foi dans
Je voudrais convaincre même celui qui en doute qu'il n'y a pas
Je sais combien est grande votre attente d'un changement profon
Je sais les craintes que beaucoup d'entre vous éprouvent pour l
Je sais l'angoisse qui vous étreint quand vous avez peur de per
Je sais votre exaspération quand vous voulez entreprendre ou qu
je le ferai. Je le ferai tout simplement parce que c'est l'inté
je vous avais faite de vous rendre la fierté d'être Français, d
je veux dire que j'ai fait tout ce que je pensais possible de f
Je ne crois pas à la brutalité comme méthode de gouvernement. J
je me suis efforcé dans le respect de tous.
je veux dire qu'il ne faut pas perdre de vue que notre pays a t
je n'ai agi qu'avec le souci de défendre les intérêts de la Fra
je ne me sois répété l'engagement que j'ai pris envers chacun d
Je ne vous tromperai pas, je ne vous trahirai pas ». Je vous do
Je vous la dirai toujours. Je ne m'autoriserai aucune hypocrisi
je l'ai faite avec des hommes et des femmes de valeur. Je ne le
Je leur ai simplement proposé de servir leur pays. Ils l'ont ac
Je leur en suis reconnaissant.
je n'ai jamais cessé de penser qu'elle était indispensable. Urg
Je souhaite du fond du coeur qu'elle soit pour la France, pour
---- VOEUX08.txt
je veux penser d'abord à ceux que la vie a durement éprouvés, à
Je veux penser à nos soldats qui en ce moment même risquent leu
Je veux penser à leurs familles qui vivent douloureusement cett
je mesure la responsabilité qui est la mienne. Cette responsabi
je l'assumerai pour que tous ceux qui en ont besoin soient prot
je vous ai toujours dit la vérité et j'ai agi. C'était mon devo
je reste persuadé que le monde a besoin d'une Europe forte, ind
Je suis plus décidé que jamais à y faire face, avec le souci de
Je ne laisserai pas les plus fragiles se débattre seuls dans le
Je pense aussi à la réforme du lycée qui est nécessaire pour év
Je pense enfin à la réforme de notre procédure pénale si import
je les mènerai avec le Premier ministre François Fillon et le g
je me rendrai dès lundi parce que c'est la vocation de la Franc
je veux le relever avec vous. Vous pouvez compter sur moi.
je présente à chacun d'entre vous mes meilleurs voeux pour 2009
---- VOEUX09.txt
Je pense en particulier à ceux qui ont perdu leur emploi. Cepen
Je veux rendre hommage ce soir au sang-froid et au courage des
Je veux rendre un hommage particulier aux partenaires sociaux q
je ne suis pas un homme qui renonce à la première difficulté, e
Je sais qu'elles ont bouleversé des habitudes et qu'avant de pr
Je le conduirai avec le Premier Ministre et le Gouvernement dan
je forme pour notre pays.
je veux dire ma détermination à ce que la République tienne à l
je veux dire ce soir qu'ils ne seront pas abandonnés. Face à l'
je souhaite que 2010 soit l'année où nous redonnerons un sens a
---- VOEUX74.txt
JE VAIS VOUS PARLER, JE NE VOUDRAIS NI VOUS ENNUYER, NI VOUS AT
JE VOUS AI DEJA DECRITES ET DONT J'AURAI L'OCCASION DE VOUS PAR
JE VOUDRAIS QUE MES VOEUX SOIENT VRAIMENT DES VOEUX, LES VOEUX
JE SOUHAITE, AU NOM DE LA FRANCE, QUE LA SOCIETE FRANCAISE VOUS
JE SOUHAITE QUE 1975 SOIT L'ANNEE DE LA FRATERNITE, C'EST-A-DIR
JE PENSE AUX AGRICULTEURS, JE PENSE AUX ARTISANS, DONT LES COND
JE PENSE A CERTAINES PETITES ENTREPRISES - DEVRONT ETRE EXAMINE
JE SOUHAITE DONC QUE 1975 SOIT L'ANNEE DE LA FRATERNITE ET QU'A
JE SOUHAITE QUE LA FRANCE, EN 1975, CONTINUE DE JOUER CE ROLE,
JE LUI SOUHAITE, DANS LE MONDE TOURMENTE OU NOUS VIVONS, D'APPA
JE VOUDRAIS LES ADRESSER A CERTAINES CATEGORIES DE FRANCAIS ET,
JE NE SAIS PAS SI VOUS AVEZ PU LE VOIR, ILS M'ONT RECU AVEC LEU
JE SUIS RENTRE DES ANTILLES, MES MAINS ETAIENT COUVERTES DES EC
JE LEUR SOUHAITE, A EUX, A NOS AUTRES COMPATRIOTES DES DEPARTEM
JE PENSE AUSSI AUX FRANCAIS INSTALLES A_L_ETRANGER QUI FONT PAR
JE VOUDRAIS EN VOTRE NOM M'ADRESSER CE SOIR AUX PLUS MALHEUREUX
JE VEUX DIRE D'ABORD LES VICTIMES DES ACCIDENTS CRUELS, ET NOTA
JE PENSE AUSSI AUX FRANCAIS QUI SONT CE SOIR DANS LES HOPITAUX,
JE VOUDRAIS EGALEMENT ADRESSER NOTRE SALUT AUX TRAVAILLEURS IMM
JE VOUDRAIS ENFIN, PENSANT A LA FRANCE A LA FOIS CHRETIENNE ET
JE SOUHAITE QUE TU SOIES UNE ANNEE ACCUEILLANTE POUR LES FRANCA
---- VOEUX75.txt
JE VOUDRAIS, CE SOIR, PRESIDENT DE TOUS LES FRANCAIS, QUE MES V
JE SOUHAITE QUE L'ANNEE 1976 CONTRIBUE AU RAYONNEMENT DE LA FRA
JE RAYONNEMENT ET NE DIS-JE PAS GRANDEUR ? PARCE QUE LA GRANDEU
JE LE SOUHAITE POUR ELLE ET POUR LE MONDE
JE SOUHAITE QUE CE SOIT A VOTRE AVANTAGE, AFIN QUE VOUS VIVIEZ
JE SUIS SUR QUE CELA NE LUI REND PAS SERVICE. JE NE CROIS PAS Q
JE SOUHAITE L'ENTENTE ET L'UNITE DES FRANCAIS. CE NE SERAIT REN
JE SOUHAITE, AU NOM DE LA FRANCE UNE BONNE ET HEUREUSE ANNEE 19
JE CROIS QU'ANNE AYMONE VEUT AUSSI VOUS ADRESSER SES VOEUX
---- VOEUX79.txt
JE VOUS ADRESSE LES SOUHAITS QUE LES FRANCAIS ECHANGENT ENTRE E
JE SUIS CONDUIT A PENSER TOUS LES JOURS A LA FRANCE DANS LE MON
JE SOUHAITE QU'EN 1979, LA FRANCE FASSE RAYONNER SON MESSAGE DE
JE REVIENS D'AFRIQUE. DANS TROIS JOURS, J'ACCUEILLERAI EN TERRE
JE ME RENDRAI EN UNION SOVIETIQUE 'URSS'. PENDANT LES SIX PROCH
JE M'EFFORCE D'AFFIRMER L'IMAGE DE LA FRANCE, CELLE D'UN PAYS O
JE SOUHAITE QU'EN 1979 NOUS NOUS ORGANISIONS POUR PREPARER L'AV
JE TIENS A LE DIRE, DES UNS ET DES AUTRES. C'EST NOTRE BIEN LE
---- VOEUX83.txt
je souhaite que l'an nouveau donne des raisons d'espérer.
je ne promets rien d'autre à personne que la poursuite, sans fa
je soutiendrai demain qu'il devait y avoir équilibre des forces
je ne me lasserai jamais d'espérer - ni de vouloir - que les Fr
---- VOEUX87.txt
je vous y invite chaque fois, pour ceux qui seront seuls, âgés,
je crois, que d'exprimer au nom de tous la fraternité qui nous
Je forme des voeux, simplement, pour qu'on s'y aime un peu plus
Je désire, précisément, réfléchir avec vous à trois des rendez-
Je souhaite ardemment qu'ils se reprennent et que la France, un
je veux dire l'élection présidentielle.
Je n'établirai pas ici la liste de ces choix. Les candidats s'e
---- VOEUX89.txt
Je suis persuadé qu'elle a, par sa seule existence, puissamment
je compte voir naître dans les années 90 une confédération euro
je me disais que nous avions de la chance, nous Français, de vi
je pensais aussi qu'il nous fallait en être dignes. Les peuples
Je forme des voeux pour que la France échappe aux entraînements
Je forme des voeux, et le gouvernement y travaille, pour que la
Je forme des voeux pour que de grands chantiers tels que le log
Je souhaite de toutes mes forces que la France offre à ceux qui
---- VOEUX90.txt
je ne veux pas que cela recommence.
je crois encore aux chances de la paix et la France y travaille
Je l'ai dit à la tribune des Nations unies, le 24 septembre der
Je souhaite qu'il s'organise dans le cadre d'une ou plusieurs c
Je me souviens de vous avoir déclaré lors des premiers voeux qu
je vous adressais, le 31 décembre 1981 : "Tout ce qui permettra
Je suis frappé du décalage qui existe entre la réalité de notre
Je sais ce qui ne va pas chez nous. Je sais aussi ce qui va bie
je n'ignore pas que nous avons besoin de bien d'autres choses e
---- VOEUX94.txt
je dois redire l'admiration que m'inspire l'extraordinaire coup
Je pense, en particulier, à l'équipage d'Air-France dont le san
je trouve dans ces faits un véritable réconfort. Il est bon de
Je constate seulement que les efforts accomplis par les uns et
je m'adresse à vous pour des voeux de nouvelle année en ma qual
je me permettrai deux recommandations : la première : ne dissoc
Je vous le dis avec la même passion que naguère. N'en doutez pa
Je n'apprendrai rien à personne en rappelant que dans quatre mo
Je souhaite vivement que ce soit l'occasion d'un vrai, d'un gra
je serai, je l'écouterai le coeur plein de reconnaissance pour
Je crois aux forces de l'esprit et je ne vous quitterai pas. Je

Exercice 6 : chercher un autre motif dans un texte

Pour les mots securite ou insecurite, on construit l’expression :

import pyensae, re
discours = pyensae.download_data('voeux.zip', website = 'xd')

exp = re.compile ("(.{1,15}(in)?sécurité.{1,50})", re.IGNORECASE)
for fichier in discours :
    print("----",fichier)
    try:
        with open(fichier,"r") as f :  text = f.read()
    except:
        with open(fichier,"r", encoding="latin-1") as f :  text = f.read()
    je = exp.findall(text)
    for t in je :
            print (t)
---- VOEUX01.txt
("enacée quand l'insécurité progresse, quand l'exercice des libertés, la qual", 'in')
---- VOEUX05.txt
---- VOEUX06.txt
("traites, notre sécurité sociale se réforment et c'est la garantie de leur", '')
("rvice, pour la sécurité, pour l'emploi, pour le pouvoir d'achat et que ce", '')
(" l'énergie, la sécurité, l'immigration. N'oublions jamais que l'Europe, c", '')
---- VOEUX07.txt
---- VOEUX08.txt
('vie pour notre sécurité et pour la paix. Je veux penser à leurs familles ', '')
---- VOEUX09.txt
('garantir notre sécurité.', '')
---- VOEUX74.txt
---- VOEUX75.txt
---- VOEUX79.txt
---- VOEUX83.txt
("tres : plus de sécurité, des banlieues rénovées et plus d'enfants dans no", '')
---- VOEUX87.txt
---- VOEUX89.txt
(' de paix et de sécurité.', '')
---- VOEUX90.txt
(' du Conseil de sécurité, organe suprême des Nations unies. A ce titre, no', '')
(' du Conseil de sécurité, y compris le recours éventuel à la force. Voilà ', '')
(" d'Israël à la sécurité, ni le droit des Palestiniens à posséder une patr", '')
---- VOEUX94.txt

Exercice 7 : recherche les urls dans une page wikipédia

On pourra prendre comme exemple la page du programme Python. La première partie consiste à récupérer le contenu d’une page HTML.

from urllib.request import urlopen
url = "https://fr.wikipedia.org/wiki/Python_(langage)"
with urlopen(url) as u:
    content = u.read()
content[:100]
b'<!DOCTYPE html>n<html class="client-nojs" lang="fr" dir="ltr">n<head>n<meta charset="UTF-8"/>n<title'

Les données récupérées sont au format binaire d’où le préfixe b''. Pour éviter de télécharger les données à chaque fois, on sauve le contenu sur disque pour le récupérer la prochaine fois.

with open('page.html', 'wb') as f:
    f.write(content)

Et on le recharge.

with open('page.html', 'rb') as f:
    page = f.read()
page[:100]
b'<!DOCTYPE html>n<html class="client-nojs" lang="fr" dir="ltr">n<head>n<meta charset="UTF-8"/>n<title'

Les données sont sous forme d’octets, il faut d’abord les convertir sous forme de caractères. il y a plus de caractères que d’octets disponibles (256), c’est cela qu’il faut une sorte de code pour passer de l’un à l’autre : dans le cas d’internet, le plus utilisé est l’encoding utf-8.

page_str = page.decode('utf-8')
page_str[:100]
'<!DOCTYPE html>n<html class="client-nojs" lang="fr" dir="ltr">n<head>n<meta charset="UTF-8"/>n<title'

On recherche maintenant les urls commençant par http…

import re
reg = re.compile("href=\\\"(http.*?)\\\"")
urls = reg.findall(page_str)
urls[:10]
['https://fr.wikipedia.org/wiki/Python_(langage)',
 'https://www.wikidata.org/wiki/Q28865?uselang=fr#P348',
 'http://www.python.org/',
 'https://www.wikidata.org/wiki/Q28865?uselang=fr#P1195',
 'https://en.wikipedia.org/wiki/Amoeba_(operating_system)',
 'https://en.wikipedia.org/wiki/Corporation_for_National_Research_Initiatives',
 'https://en.wikipedia.org/wiki/C3_linearization',
 'https://en.wikipedia.org/wiki/Pyglet',
 'https://en.wikipedia.org/wiki/Unladen_Swallow',
 'https://en.wikipedia.org/wiki/Math_Kernel_Library']

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.

patron = """
<ul>{% for i, url in enumerate(urls) %}
  <li><a href="{{ url }}">url {{ i }}</a></li>{% endfor %}
</ul>
"""
from jinja2 import Template
tpl = Template(patron)
print(tpl.render(urls=urls[:10], enumerate=enumerate))
<ul>
  <li><a href="https://fr.wikipedia.org/wiki/Python_(langage)">url 0</a></li>
  <li><a href="https://www.wikidata.org/wiki/Q28865?uselang=fr#P348">url 1</a></li>
  <li><a href="http://www.python.org/">url 2</a></li>
  <li><a href="https://www.wikidata.org/wiki/Q28865?uselang=fr#P1195">url 3</a></li>
  <li><a href="https://en.wikipedia.org/wiki/Amoeba_(operating_system)">url 4</a></li>
  <li><a href="https://en.wikipedia.org/wiki/Corporation_for_National_Research_Initiatives">url 5</a></li>
  <li><a href="https://en.wikipedia.org/wiki/C3_linearization">url 6</a></li>
  <li><a href="https://en.wikipedia.org/wiki/Pyglet">url 7</a></li>
  <li><a href="https://en.wikipedia.org/wiki/Unladen_Swallow">url 8</a></li>
  <li><a href="https://en.wikipedia.org/wiki/Math_Kernel_Library">url 9</a></li>
</ul>