Mini-projet

Identification

Infoforall

15 - Mini-projet avec FOR et IF


Maintenant que vous avez vu quatre fondamentaux de la programmation (fonction, boucle bornée, instruction conditionnel et tableaux), nous allons pouvoir les utiliser en même temps pour commencer à réaliser des choses vraiment longues voire impossible à réaliser à la main.

Je présente donc ici une activité très détaillée, la plupart du temps il suffit de faire du copier-coller. Mais vous pourrez voir que vous avez bien progressé et qu'on peut maintenant faire des choses assez complexes lorsqu'on mélange toutes ces notions en même temps.

On retrouve bien entendu le principe "une tâche - une fonction".

Evaluation ✎ : -

Documents de cours FOR : open document ou pdf

Documents de cours IF : open document ou pdf

1 - Evaluer le thème d'un texte : les fonction basiques

Aucune des fonctionnalités vues ici n'est à connaître par coeur.

Il s'agit juste de vous le faire réaliser, pas de vous demander de savoir le refaire en DS.

Voyons comment trouver le thème d'un texte en analysant les mots qu'il contient pour tenter d'en déduire vaguement de quoi il parle. On pourrait tenter de trouver les catégories suivantes :

  • compteur_amour,
  • compteur_amitie,
  • compteur_mort,
  • compteur_guerre,
  • compteur_politique,
  • compteur_economie,
  • compteur_famille,
  • compteur_science,
  • ...

Pour les textes, nous prendrons des textes de chansons par exemple. C'est assez facile à trouver sur le Web.

Pour ce TP, nous prendrons le texte d'une chanson de Stromae, comme cela tout le monde connait. Mais vous pouvez bien entendu faire la même chose avec n'importe quel texte..

Dans cette partie, nous allons voir comment réaliser deux fonctionnalités basiques :

  1. Le prédicat detecter_le_mot() : elle va détecter la présence d'un mot dans un texte donné et renvoyer
  2. La fonction generer_tableau_des_mots() : cette fonction va renvoyer un tableau contenant dans chaque case les mots contenus dans un string d'entrée :
    • Si on lui envoie le string "hamburger, frite, mayo" pour détecter la malbouffe,
    • elle va renvoyer le tableau ["hamburger""frite""mayo"]

01° Mettre le programme ci-dessous en mémoire. La constante TEXTE est un string multiligne pouvant contenir des guillemets : on utilise 3 guillemets (""") en tant que séquence d'ouverture du string et on finalise le string avec une autre séquence """.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
# 1 - Partie Importation # 2 - Partie Déclaration des CONSTANTES TEXTE = """ Dites-moi d'où il vient Enfin je saurai où je vais Maman dit que lorsqu'on cherche bien On finit toujours par trouver Elle dit qu'il n'est jamais très loin Qu'il part très souvent travailler Maman dit "Travailler c'est bien" Bien mieux qu'être mal accompagné! Pas vrai? Où est ton papa? Dis-moi, où est ton papa? Sans même devoir lui parler Il sait ce qu'il ne va pas Un sacré papa Dis-moi où es-tu caché? Ça doit faire au moins mille fois Que j'ai compté mes doigts Où t'es? Papa où t'es? Où t'es? Papa où t'es? Où t'es? Papa où t'es? Où t'es? Où t'es? Où Papa où t'es? Où t'es? Papa où t'es? Où t'es? Papa où t'es? Où t'es? Papa où t'es? Où t'es? Où t'es? Où Papa où t'es? Où t'es? Quoi, qu'on y croit ou pas Il y aura bien un jour où on n'y croira plus Un jour où l'autre on sera tous papa Et d'un jour à l'autre, on aura disparu Serons-nous détestables? Serons-nous admirables? Des géniteurs ou des génies Dites-nous qui donne naissance aux irresponsables? Ah, dites-nous qui, tiens Tout le monde sait comment on fait des bébés Mais personne ne sait comment on fait des papas Monsieur je sais tout en aurait hérité, c'est ça? Il faut le sucer de son pouce où quoi? Dites-nous où c'est caché? Ça doit faire au moins mille fois Qu'on a bouffé nos doigts Où t'es? Papa où t'es? Où t'es? Papa où t'es? Où t'es? Papa où t'es? Où t'es? Où t'es? Où Papa où t'es? Où t'es? Papa où t'es? Où t'es? Papa où t'es? Où t'es? Papa où t'es? Où t'es? Où t'es? Où Papa où t'es? Où t'es? Où est ton papa? Dis-moi, où est ton papa? Sans même devoir lui parler Il sait ce qu'il ne va pas Un sacré papa Dis-moi où es-tu caché? Ça doit faire au moins mille fois Que j'ai compté mes doigts Où est ton papa? Dis-moi, où est ton papa? Sans même devoir lui parler Il sait ce qu'il ne va pas Un sacré papa Dis-moi où es-tu caché? Ça doit faire au moins mille fois Que j'ai compté mes doigts Où t'es? Papa où t'es? Où t'es? Papa où t'es? Où t'es? Papa où t'es? Où t'es? Où t'es? Où Papa où t'es? Où t'es? Papa où t'es? Où t'es? Papa où t'es? Où t'es? Papa où t'es? Où t'es? Où t'es? Où Papa où t'es? Où t'es? """ # Partie 3 - Déclaration des fonctions # Partie 4 - Programme principal compteur_amour = 0 compteur_amitie = 0 compteur_mort = 0 compteur_guerre = 0 compteur_politique = 0 compteur_economie = 0 compteur_famille = 0 compteur_science = 0 compteur_sante = 0 if 'mort' in TEXTE: compteur_mort = compteur_mort + 1 if 'décès' in TEXTE : compteur_mort = compteur_mort + 1 if 'amour' in TEXTE: compteur_amour = compteur_amour + 1 if 'amoureux' in TEXTE: compteur_amour = compteur_amour + 1 if 'papa' in TEXTE: compteur_famille = compteur_famille + 1 if 'maman' in TEXTE: compteur_famille = compteur_famille + 1

On retrouve les différentes parties d'un programme :

  1. D'abord les importations (aucune ici)
  2. Ensuite les CONSTANTES et les variables globales modifiées par les fonctions (uniquement le string TEXTE ici)
  3. Puis la déclaration des fonctions (aucune pour l'instant)
  4. Enfin, le programme principal en lui même.

Le programme est assez simple :

  • Lignes 91 à 99 : on déclare et initialise un certain nombre de compteurs thématiques : ces variables vont s'incrémenter à chaque fois qu'un mot correspondant à un thème particulier apparaît.
  • 91 92 93 94 95 96 97 98 99
    compteur_amour = 0 compteur_amitie = 0 compteur_mort = 0 compteur_guerre = 0 compteur_politique = 0 compteur_economie = 0 compteur_famille = 0 compteur_science = 0 compteur_sante = 0
  • Lignes 101 à 104 : on incrémente le compteur compteur_mort si on détecte au moins une fois le string "mort" puis la même chose avec le mot "décès" car ils sont du champ lexical de la mort.
  • 91 92 93 94
    if 'mort' in TEXTE: compteur_mort = compteur_mort + 1 if 'décès' in TEXTE : compteur_mort = compteur_mort + 1
  • Les lignes suivantes correspondent au même principe pour d'autres thèmes.

Deux mots par thème pour l'instant, ce n'est pas énorme.

02° Deux questions :

  1. Quels sont les deux mots associés au thème famille pour l'instant ?
  2. Le compteur compteur_famille devrait atteindre 2 puisque ces deux mots apparaissent dans le texte. Pourquoi le compteur n'atteint-il que 1 ?
>>> compteur_famille >>> 1

...CORRECTION...

Les deux mots sont visibles lignes 111-113 : "papa" et "maman".

Pour le nombre, c'est facile lorsqu'on a vu le petit détail : à cause des majuscules !

Python est sensible à la casse : les strings "Papa" et "papa" sont deux strings différents.

Or, "papa" apparaît bien une fois, mais pas pas "maman". C'est "Maman" qui apparaît en ligne 8.

03° Utiliser ces instructions dans la console. Que constatez-vous sur

  1. le string new1 après application de la méthode lower() des strings, et
  2. le string new2 après application de la méthode upper() des strings  ?
>>> TEXTE = "BoNJoUr à TOUS, et à tOutes !" >>> TEXTE 'BoNJoUr à TOUS, et à tOutes !' >>> new1 = TEXTE.lower() >>> new1 ??? >>> new2 = TEXTE.upper() >>> new2 ???

On remarquera qu'on utilise, comme avec le module turtle, des méthodes : des sortes de "fonctions" intégrées de base à certains types d'objets : ici les strings. La façon de les utiliser est toujours la même :

une_variable.une_methode()

...CORRECTION...

>>> TEXTE = "BoNJoUr à TOUS, et à tOutes !" >>> TEXTE 'BoNJoUr à TOUS, et à tOutes !' >>> new1 = TEXTE.lower() >>> new1 'bonjour à tous, et à toutes !' >>> new2 = TEXTE.upper() >>> new2 'BONJOUR À TOUS, ET À TOUTES !'

Les deux méthodes portent donc bien leurs noms. Elles renvoient une nouvelle version du string, soit en minuscules (lowercase en anglais), soit en majuscules (uppercase en anglais).

Nous allons donc plutôt faire travailler nos recherches sur le texte transformé intégralement en minuscules pour être certain de trouver le mot : la recherche de Papa, PAPA, papa, ou pApA donnera de cette façon toujours un résulat positif puisqu'ils seront tous transformés en papa.

  • "Papa".lowercase() renvoie "papa"
  • "PAPA".lowercase() renvoie "papa"
  • "papA".lowercase() renvoie "papa"
ATTENTION : dans la suite de l'activité, je ne redonne plus la chanson, juste sa position. A vous de faire attention à vos copier-coller : laissez bien l'intégralité du texte de la constante TEXTE.

04° Utiliser le "nouveau" programme qui travaille sur une version en minuscules de la chanson : copier-coller et modifier uniquement les lignes 101 et plus pour modifier les anciennes lignes équivalentes. Obtient-on bien deux points pour le champ lexical de la famille ?

1 2 3 4 5 6 7 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
# 1 - Partie Importation # 2 - Partie Déclaration des CONSTANTES TEXTE = """ Dites-moi d'où il vient ... Où t'es? """ # Partie 3 - Déclaration des fonctions # Partie 4 - Programme principal compteur_amour = 0 compteur_amitie = 0 compteur_mort = 0 compteur_guerre = 0 compteur_politique = 0 compteur_economie = 0 compteur_famille = 0 compteur_science = 0 compteur_sante = 0 texte = TEXTE.lower() if 'mort' in texte: compteur_mort = compteur_mort + 1 if 'décès' in texte: compteur_mort = compteur_mort + 1 if 'amour' in texte: compteur_amour = compteur_amour + 1 if 'amoureux' in texte: compteur_amour = compteur_amour + 1 if 'papa' in texte: compteur_famille = compteur_famille + 1 if 'maman' in texte: compteur_famille = compteur_famille + 1

...CORRECTION...

>>> famille 2

Oui, cette fois le programme a bien réussi à gérer la présence de "maman" même si il est présent sous la forme "Maman".

Par contre, vous pouvez remarquer qu'on utilise souvent le même type d'instructions sur les lignes 103 à 116. Il serait sans doute malin de réaliser une fonction pour automatiser tout cela.

05° Etude théorique, ne lancez pas le programme : Que renvoie la fonction detecter_le_mot() si le mot envoyé dans le paramètre mot est présent dans le paramètre texte ? Et si le mot n'est pas présent ?

89 90 91 92 93 94
def detecter_le_mot(mot:str, texte:str) -> int: """Renvoie 1 si on détecte la présence du mot dans le string fourni, 0 sinon""" reponse = 0 if mot in texte: reponse = 1 return reponse

...CORRECTION...

>>> famille 2

Si le mot est détecté, la fonction va renvoyer 1.

Si le mot n'est pas détecté, la valeur initiale de la réponse n'est pas modifiée et on renvoie donc 0.

06° Etude théorique également : on considère que le compteur compteur_famille vaut 0 initialement.

Que contient le compteur après exécution de la ligne 116 si on considère que le mot cherché est bien détecté ?

Que contient le compteur après exécution de la ligne 117 si on considère que le mot cherché est également présent ?

116 117
compteur_famille = compteur_famille + detecter_le_mot("papa", texte) compteur_famille = compteur_famille + detecter_le_mot("maman", texte)

...CORRECTION...

En L116, on commence donc par lancer l'appel à la fonction. Elle répond 1 puisqu'on détecte le mot nous dit l'énoncé.

116
compteur_famille = compteur_famille + 1

Ensuite, on évalue la variable compteur_famille qui fait référence à 0 pour l'instant.

116
compteur_famille = 0 + 1

Le calcul donne donc 1 et il ne reste plus qu'à l'affecter comme nouvelle valeur de la variable compteur_famille.

En L117, on commence donc par lancer l'appel à la fonction. Elle répond 1 puisqu'on détecte le mot nous dit l'énoncé.

117
compteur_famille = compteur_famille + 1

Ensuite, on évalue la variable compteur_famille qui fait référence à 1 pour l'instant.

116
compteur_famille = 1 + 1

Le calcul donne donc 2 et il ne reste plus qu'à l'affecter comme nouvelle valeur de la variable compteur_famille.

07° Utiliser le nouveau programme pour vérifier qu'il réagit comme l'ancien. Attention à TEXTE que je n'ai pas reproduit intégralement.

1 2 3 4 5 6 7 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
# 1 - Partie Importation # 2 - Partie Déclaration des CONSTANTES TEXTE = """ Dites-moi d'où il vient ... Où t'es? """ # Partie 3 - Déclaration des fonctions def detecter_le_mot(mot:str, texte:str) -> int: """Renvoie 1 si on détecte la présence du mot dans le string fourni, 0 sinon""" reponse = 0 if mot in texte: reponse = 1 return reponse # Partie 4 - Programme principal compteur_amour = 0 compteur_amitie = 0 compteur_mort = 0 compteur_guerre = 0 compteur_politique = 0 compteur_economie = 0 compteur_famille = 0 compteur_science = 0 compteur_sante = 0 texte = TEXTE.lower() compteur_mort = compteur_mort + detecter_le_mot("mort", texte) compteur_mort = compteur_mort + detecter_le_mot("décès", texte) compteur_amour = compteur_amour + detecter_le_mot("amour", texte) compteur_amour = compteur_amour + detecter_le_mot("amoureux", texte) compteur_famille = compteur_famille + detecter_le_mot("papa", texte) compteur_famille = compteur_famille + detecter_le_mot("maman", texte)

Bon, c'est bien gentil deux mots par champ lexical mais si j'en veux plus ?

Dans ce cas, il va falloir taper beaucoup d'appels à la fonction detecter_le_mot()...

Comment faire mieux ? En plaçant les mots associés à un thème dans un tableau et lire une à une toutes les cases du tableau.

08° Placer ce nouveau programme en mémoire en remplacement total de l'ancien pour le moment. Répondre ensuite aux cinq questions suivantes :

1 2 3 4
mots_guerre = ['guerre', 'conflit', 'arme', 'armement', 'blessé', 'tuerie', 'massacre', 'armée', 'militaire', 'bombe'] for i in range( len(mots_guerre) ): # i vaut 0, puis 1... print(mots_guerre[i])
  1. Que veut dire en français la ligne suivante en traduction "mot à mot" ?
  2. 3
    for i in range( len(mots_guerre) ): # i vaut 0, puis 1...
  3. Que comprend l'interpréteur Python si vous tapez ceci ?
  4. 4
    print(i)
  5. Que comprend l'interpréteur Python lorsqu'on écrit ceci dans le programme :
  6. 4
    print(mots_guerre[i])
  7. Que veut dire en français la ligne suivante en traduction "mot à mot" ?
  8. 3
    for i in range( len(mots_guerre) ): # i vaut 0, puis 1...
  9. Expliquer pourquoi le programme affiche ceci :
  10. guerre conflit arme armement blessé tuerie massacre armée militaire bombe

...CORRECTION...

  1. Cette ligne veut dire "Pour chaque indice i variant de 0 au nombre de cases du tableau moins un".
  2. On le traduira plutôt par "Pour chaque indice possible du tableau"
  3. Avec print(i), on transmet juste i dans la fonction native print(). Python va donc comprendre qu'on lui demande d'afficher le NUMERO de la case.
  4. Avec print(mots_guerre[i]), on demande cette fois d'afficher le CONTENU de la case i du tableau mots_guerre.
  5. Puisque le tableau possède 10 cases, l'interpréteur va réaliser ceci :
  6. 3 4
    for i in range(10) : # pour i variant de 0 à 9 print(mots_guerre[i])

    range(10) va générer l'ensemble d'indices suivant :

    3 4
    for i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]: # on récupére dans i un par un les indices disponibles print(mots_guerre[i])

    Cela veut donc dire qu'on va exécuter la ligne 4 avec d'abord un indice de 0 :

    4
    print(mots_guerre[0])

    Puis un indice de 1 :

    4
    print(mots_guerre[1])

    Ect... jusqu'à atteindre la dernière valeur, 9 :

    4
    print(mots_guerre[2]) print(mots_guerre[3]) print(mots_guerre[4]) print(mots_guerre[5]) print(mots_guerre[6]) print(mots_guerre[7]) print(mots_guerre[8]) print(mots_guerre[9])

09° Faire des recherches sur le Web, avec un moteur de recherche, en utilisant ces mots-clés :

  • "champ lexical mort"
  • "champ lexical guerre"
  • "champ lexical amour"
  • "champ lexical famille"

Vous devriez tomber assez facilement sur des sites proposant un ensemble de mots liés au thème cherché.

...CORRECTION...

Pour la mort, nous avons par exemple :

défunt, cadavre, résurrection, tombeau, cercueil, agonie, euthanasie, vie, dépouille, deuil, décès, meurtre, suicide, pendu, ressusciter, posthume, exécution, Mânes, tombe, funèbre, cimetière, disparu, supplice, immortalité, mourir, vivant, assassinat, enterrement, faucheuse, autopsie, mortel, mortuaire, noyé, trépas, enfer, funéraire, blessé, perte, strangulation, survivant, crémation, éternité, glas, pendaison, tué, claqué, noyade, destruction, immortel, catastrophe, disparition, feu, meurtrier, ombre, spiritisme, tragique, trépassé, assassin, Hadès, paradis, repos, succession, vieillesse, corbillard, dernier souffle, extrême-onction, funérailles, funeste, ivre, mourant, belle mort, bourreau, camarde, fossoyeur, inanimé, macchabée, mort-vivant, Thanatos, âme, crevé, désolation, sépulture, thanatologie, enterré, épitaphe, porté disparu, spectre, taxidermie, embaumement, linceul, martyr, martyre, matador, métempsycose, nécromancie, religion, Requiem, vampire, châtiment, coroner, dernier soupir, guillotine, mémoire, néant, poison, sauver, suicider, apoptose, évanoui, infarctus du myocarde, macabre, nécrose, relique, survie, torture, assassiné, bûcher, canné, désert, échafaud, fatigué, foutu, naze, sépulcre, chagrin, charogne, condamné, crime, empoisonnement, malemort, mort-né, proscription, pulsion, puni, régicide, six pieds sous terre, victime, violente, cénotaphe, cinéraire, décédé, ensevelissement, gisant, limbe, maladie, messe, mortalité, nuit, peine capitale, pendre, regretter, venger, cendre, fosse, gibet, parque, pécheur, sommeil, supplicié, testament, charnier, commémoration, danger, ensevelir, heure suprême, piqûre, prématurée, purgatoire, seuil, veuve, certaine, décapité, étranglé, imminente, menacer, venin, vie éternelle, asphyxie, Charon, corps, esprit, exécuter, foudroyant, inerte, post-mortem, ruine, achever, anéantissement, apothéose, croque-mort, crucifié, crypte, éteint, exténué, extinction, fantôme, morgue, mors, Nécrologie, Odin, péché, pourriture, Vallée de la mort, attentat, autre monde, champ de bataille, crématoire, décapitation, dernier adieu, déterrer, empoisonné, génocide, heure dernière, inhumé, intestat, nécromasse, nécrophile, outre-tombe, psychopompe, regret, repos éternel, reste, sarcophage, suaire, survivance, valkyrie, viatique, accidentelle, agonisant, descente aux enfers, douloureuse, épuisé, fin, frôlé, fusillade, instantanée, lente, létal, monument, mortifère, naissance, nécrophilie, oraison funèbre, succéder, suppression, accident de la route, atroces, condamnation, décimer, délivrera, élégie, épouvante, éternelle, honorer, incinération, inhumation, jonchée, menace, mort subite, naufrage, obsèques, ossements, peine, pleurer, présage, souffrance, surdose, survenue, terrible, vaincu, annoncée, anticipée, au-delà, blessure, coma, condamnent, cruel, écroulement, homicide, horrible, ignominie, messager, parricide, sauveur, tuant, vengeance, à plat, aboutissement, ankylosé, apathique, bienheureux, bousillé, brisé, cassé, chute, conclusion, décomposition, défunction, délavé, dénouement

Pour la guerre, nous avons par exemple :

ennemi, conflit, paix, stratégie, guérilla, hostilité, bataille, militaire, artillerie, armement, tactique, expédition, famine, mobilisation, belligérant, après-guerre, armée, soldat, belliqueux, neutralité, camp, conquête, arme, invasion, lutte, guerre civile, indépendance, libération, stratégique, victoire, combat, guerroyer, croiseur, guerrier, campagne, coalition, offensive, stratège, conscription, état-major, frontière, incursion, révolution, alliance, Vichy, armistice, corsaire, cuirassé, flotte, maritime, nation, religion, sécession, territoire, attaque, belliciste, escadre, front, guerre mondiale, sous-marin, violence, catapulte, désarmement, insurrection, pacifique, Société des Nations, affrontement, amirauté, corvette, ghetto, punique, résistance, agression, civil, combattant, défense, diplomatie, djihad, extermination, génocide, impérialisme, mars, pacifiste, seconde guerre mondiale, trêve, ultimatum, belligérance, bombardement, cessez-le-feu, commandant, croisade, impérialiste, OTAN, Verdun, annexion, Arès, assaut, généralissime, infanterie, nucléaire, terrorisme, cavalerie, confédération, contre-torpilleur, dévastation, dissension, Grande Guerre, Napoléon, obus, allié, bellicisme, blocus, capitaine, déclaration de guerre, dictature, entre-deux-guerre, franco-allemande, kamikaze, munition, nationalisme, Péloponnèse, polémologie, prisonnier de guerre, Vercingétorix, bombe, envahisseur, force, fronde, galère, Hannibal, massacre, mobilisé, plan Marshall, porte-avion, propagande, représaille, Troie, bombardier, débarquement, déclarer, destroyer, gouvernement, pacifisme, aguerrir, capitulation, casus belli, fortification, fusil, guerre de Sécession, légion, meurtrière, puissance, riflette, royaume, champ de bataille, colonie, décolonisation, désastre, discorde, échec, engagement, géopolitique, guerre sainte, monarchie, ONU, opération, partisan, poilu, stalag, tomahawk, troupe, vaincre, atomique, bâtiment, commandement, conflagration, déclenchement, déclencher, destruction, fratricide, guerre d'extermination, Hitler, maréchal, occupation, perte, première guerre mondiale, prospérité, protectorat, ravagé, réparation, révolutionnaire, rivalité, sanglante, terreur, aviation, blitzkrieg, char, coloniale, combattre, Croix-Rouge, émeute, escarmouche, espionnage, exil, fascisme, harki, militarisme, Nuremberg, Pétain, renseignement, sans merci, Shoah, sino-japonaise, supériorité, torpille, Vietnam, Achille, camisard, convoi, crime, expéditionnaire, Hiroshima, lieutenant-colonel, Maginot, major, mémorial, milice, missile, nerf, parachutiste, pays, radar, ravitaillement, Rommel, superpuissance, vaincu, victorieux, agresseur, butin, chouannerie, duel, expansionniste, feu, honneur, insurgé, naval, pacification, patriotisme, pillage, soulèvement, spartiate, Armageddon, armer, collaboration, commander, disparu, division, domination, effectif, enjeu, épée, euromissile, expansion, garnison, hégémonie, indemnité, jeep, jour J, machine, martial, mener, négociation, neutre, Odin, opposition, possession, prendre, prisonnier, soutien, acharnée, aérien, approvisionnement, baïonnette, baliste, ban, Barbarossa, César, colonel, convention de Genève, déclaration, défensive, dispute, éclater, ensanglanter, épidémie, escorte, exploit, faction, forteresse, francisque

Le champs lexical de l'amour donne ceci :

amoureux, tendresse, amitié, baiser, Cupidon, Aphrodite, passion, Éros, désir, sentiment, amant, affection, idylle, Vénus, attachement, attirance, platonique, compassion, plaisir, charité, érotique, haine, relation, beauté, adoration, aimer, philtre, altruisme, amourette, bien-aimé, érotisme, joie, mariage, romantique, courtois, émotion, déesse, éternel, luxure, bonheur, conjugal, jalousie, psyché, cœur, filial, fraternel, charnel, chaste, sexualité, dévotion, ivresse, philanthropie, amour platonique, couple, fidélité, flamme, tendre, sincère, volupté, Dieu, idolâtrie, piété, souffrance, troubadour, chant, chasteté, désespoir, libertinage, romantisme, solitude, désamour, poésie, sacrifice, mépris, poème, sensualité, sexuel, chagrin, feu, loyauté, Marivaux, romance, épris, hymen, séduction, âme, dilection, lyrique, ode, thème, abnégation, bagatelle, bien-aimée, chanson, conquête, déclaration, désintéressement, fou, indifférence, passionné, adultère, amor, enchantement, femme, inceste, mystique, passionnel, paternel, respect, romanesque, concupiscence, heureux, Juliette, Musset, sonnet, tourment, tristesse, agapè, follement, fraternité, infini, mari, maternel, narcissisme, sentimental, adorable, ardeur, baise, chevaleresque, drame, égoïste, étreinte, fille, jeunesse, malheur, mélancolie, nymphe, tragique, volage, admiration, charme, coït, époux, ferveur, folie, générosité, Hélène, intrigue, Jésus, poète, tragédie, accouplement, Adonis, amour maternel, amoureusement, caprice, contemplation, coup de foudre, éprouver, héroïne, homosexuel, intimité, timide, Tristan, vénération, affective, Andromaque, aventure, confidente, coquetterie, délice, extase, galanterie, rédemption, adolescent, amante, ami, carquois, désintéressé, divin, égoïsme, enflammer, fidèle, film, gloire, hyménée, idéal, idyllique, mère, véritable, virginité, beau, cour, dévouement, garçon, immodéré, inconstance, Lancelot, naissant, récit, sensuel, aphrodisiaque, badinage, Boccace, chéri, coquin, fleurette, Héra, malheureux, mutuel, Thésée, ange, berger, croire, culte, débauche, délicatesse, effusion, élan, enivrant, enthousiasme, estime, exprimer, fée, homosexualité, Horace, inclination, mysticisme, partagé, penchant, petit copain, pulsion, relation amoureuse, rut, soupirant, sympathie, bisou, Chimène, coucher, cruel, Dante, effréné, fiançailles, foi, foutre, gaieté, Hippolyte, infidélité, inquiétude, jaloux, love, Phèdre, pitié, premier amour, Rodrigue, sacrifier, Saint-Valentin, sans espoir, sexe, sincérité, Truffaut, zoophile, Astarté, aveugle, belle âme, bonté, caresse, chérir, compagne, confidence, débordant, inaltérable, incommensurable, instinctif, intérêt, lyrisme, peinture, réciproque, rédempteur, roman, Roméo, sagesse, soufi, Stendhal, vénal, aimable, Antéros, ardent, billet doux, consume, copulation, courage, enchanteur, espérance, exaltation, fantôme, fol, folle, fusionnel, Héloïse

Pour la famille, nous avons par exemple :

parenté, filiation, familial, dynastie, généalogie, ménage, tribu, parent, clan, mère, maison, lignée, patriarche, ancêtre, entourage, oncle, enfant, sang, foyer, ordre, branche, père, souche, descendance, fratrie, frère, lignage, aîné, matriarcat, naissance, originaire, sœur, tante, grand-mère, grand-père, issu, neveu, rejeton, arbre généalogique, genre, mariage, vendetta, maisonnée, race, alliance, cousin, fille, grand-parent, prénom, sous-famille, subvenir, appartenant, beau-frère, beau-père, nièce, Benjamin, blason, héritage, mari, amérindien, caste, descendant, héréditaire, feu, inceste, nichée, belle-mère, belle-sœur, bercail, célibataire, cousine, demi-sœur, paternelle, chef de famille, membre, patrie, pension, progéniture, régnante, soutien, adoptive, amitié, dot, gendre, hôtel, modeste, nobiliaire, patricien, patronyme, propriété, bourgeoise, décès, espèce, hérédité, lien, noble, repas, résidence, aristocratique, cadette, couvée, époux, familier, patriarcat, seigneur, smala, sous-ordre, taxon, budget, communauté, composé, femme, génération, matriarche, nombreuse, nourrir, parrain, phratrie, aimante, aisée, aristocratie, condoléance, consanguinité, enfance, fief, fortune, groupe, impériale, logis, misère, oligarchie, racine, riche, surnom, bon père, caractère, de père en fils, défunt, éducation, honte, issue, orphelin, réunie, richissime, seigneurial, faire vivre, fonder, grand-oncle, hospitalité, individu, marié, monarchie, opprobre, paroisse, analogie, couple, demi-frère, fils, frères et sœurs, héritier, origine, princière, veuf, adoption, aïeul, arrière-grand-père, bru, cinéraire, classe, dernier-né, descendre, jeune, maternel, nom, orphelinat, parentèle, patrilinéaire, peuple, réunion, société, sous-espèce, tata, toit, troglodyte, union, amis, ascendance, chat, degré de parenté, déplacée, famille recomposée, fou, grand-tante, isolat, lieu, ménagère, monoparentale, portrait, proche, réveillon, sous-classe, taxinomie, tonton, venger, aînesse, cadet, chef, coutume, dans le besoin, émigrer, généalogique, gens, gouvernante, langue maternelle, matante, mononcle, noblesse, notaire, orpheline, parentalité, patriarcale, peuplade, prince, propriétaire, vacance, armoiries, attachement, catégorie, collection, décimée, deuil, fermier, fiançailles, gotha, mafieuse, médecin, nom vernaculaire, petit-fils, petits-enfants, plébéienne, précepteur, veuve, vivait, arrière-grand-mère, caveau, drame, enterrement, exil, marmaille, partager, pensionnat, persécutée, pieuse, reine, royal, Simpson, sous-genre, suite, abri, agnation, association, attroupement, belle-tante, bel-oncle, bloc, chez-soi, cognation, collectif, collège, communion, conjugal, coterie, décédé, demeure, déshonneur, ensemble, éplorée, essaim, extraction, familiariser, famille nombreuse, famille nucléaire, filleul, frère plein, garçon, gent, grappe, groupe familial, homoparentale, horde, ligne, mifa, monogamie, nettoyage, patrimoine, patronymique, peloton, portée, postérité, postnom

Voyons maintenant comment convertir ce texte (un string) en tableau : je n'ai aucunement l'intention de tout faire à la main.

Nous allons faire deux choses :

  • Supprimer les virgules en le remplaçant par une chaîne vide ("," deviendrait ""). Nous utiliserons la méthode des strings nommée replace() (remplacer en français).
  • Placer chaque mot dans une des cases d'un tableau avec la méthode des strings split() (séparer en français) qui permet de diviser un string en plusieurs parties en utilisant le séparateur indiqué et de placer les morceaux dans un tableau.

10° Placer ce nouveau programme en mémoire à la place de l'ancien. Lancer le programme, il permet de visualiser ce que provoque la méthode replace(). Répondre ensuite aux questions.

1 2 3 4 5 6 7 8 9 10 11 12 13 14
string_mots_famille = '''parenté, filiation, familial, dynastie, généalogie, ménage,""" print("----AVANT----") print(string_mots_famille) string_mots_famille = string_mots_famille.replace(',', '') print("\n----APRES----") print(string_mots_famille)

Le résultat que vous devez visualiser dans votre éditeur :

----AVANT---- parenté, filiation, familial, dynastie, généalogie, ménage, ----APRES---- parenté filiation familial dynastie généalogie ménage

Questions

  1. Quelle est la différence entre les deux affichages ?
  2. Sur quelle ligne crée-t-on le nouveau string, copie du précédent mais sans les virgules ?
  3. A quoi sert le \n qu'on transmet à la fonction native print() en ligne 13 ?

...CORRECTION...

  1. AVANT, il y a des virgules. APRES, les virgules ont été remplacées par '' et ont donc disparu.
  2. C'est la ligne 11 qui réalise ce remplacement :
  3. 11
    string_mots_famille = string_mots_famille.replace(',', '')
  4. Le symbole \n est le caractère qui permet de représenter le passage à la ligne. C'est pour cela qu'il y a un espace entre le dernier mot de AVANT et la présence de la ligne ----APRES----.
  5. 13
    print("\n----APRES----")

En réalité, le string contient donc de multiples passages à la ligne encodépar \n ou même par de façon symbolique.

----APRES---- parenté\n filiation\n familial\n dynastie\n généalogie\n ménage\n

Comment transformer ce string (qui comporte des passages à la ligne) en tableau où chaque case contient un mot. Et bien, c'est facile si on se rend compte que chaque mot est séparé des autres par le caractère de passage à la ligne. On pourra l'utiliser comme séparateur logique entre deux mots.

11° Lancer le programme ci-dessous qui vous permet de visualiser ce que provoque la méthode split(). Répondre ensuite aux questions.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
string_mots_famille = '''parenté, filiation, familial, dynastie, généalogie, ménage,""" print("----AVANT----") print(string_mots_famille) # On supprime les virgules string_mots_famille = string_mots_famille.replace(',', '') print("\n----APRES----") print(string_mots_famille) # On transforme en tableau en prenant '\n' comme séparateur tableau_mots_famille = string_mots_famille.split('\n') print("\n----AU FINAL----") print(tableau_mots_famille)

Vous devriez obtenir l'affichage suivant :

----AVANT---- parenté, filiation, familial, dynastie, généalogie, ménage, ----APRES---- parenté filiation familial dynastie généalogie ménage ----AU FINAL---- ['parenté', 'filiation', 'familial', 'dynastie', 'généalogie', 'ménage']

Questions

  1. Quel est le type Python de la variable string_mots_famille ?
  2. Quel est le type Python de la variable tableau_mots_famille ?
  3. Que vaut tableau_mots_famille[0] ?
  4. Que vaut tableau_mots_famille[1] ?
  5. Les passages à la ligne sont-ils encore présents dans les données du tableau ?

...CORRECTION...

  1. Quel est le type Python de la variable string_mots_famille ?
  2. Il s'agit d'un string, le type str de Python. On peut s'en convaincre en tapant ceci dans la console :

    >>> type(string_mots_famille)
  3. Quel est le type Python de la variable tableau_mots_famille ?
  4. Il s'agit d'un tableau qui est, en Python, le type list. On peut s'en convaincre en tapant ceci dans la console :

    >>> type(tableau_mots_famille)
  5. Que vaut tableau_mots_famille[0] ?
  6. Cette expression doit renvoyer l'élément d'indice 0 du tableau. La première case donc. Elle contient le string 'parenté''.

  7. Que vaut tableau_mots_famille[1] ?
  8. Cette expression doit renvoyer l'élément d'indice 1 du tableau. La deuxiéme case donc. Elle contient le string 'filiation'.

  9. Les passages à la ligne sont-ils encore présents dans les données du tableau ?
  10. Et non  ! Les passages à la ligne ont servi de SEPARATEUR. Ils n'apparaissent donc plus dans les valeurs stockées dans le tableau.

Il nous reste à tout simplement encapsuler cela dans une fonction.

12° Réaliser la fonction generer_tableau_des_mots() qui reçoit un string nommé string_des_mots et parvient à supprimer les virgules puis crée un tableau composé de mots EN MINUSCULES, en utilisant ce qu'on a envoyé dans le paramètre separateur comme élément séparateur des mots.

Voici son prototype :

2
def generer_tableau_des_mots(string_des_mots:str, separateur:str) -> list:

Voici le programme à compléter. La fonction renvoie pour l'instant systématiquement un tableau vide.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
# Déclaration des fonctions def generer_tableau_des_mots(string_des_mots:str, separateur:str) -> list: """Renvoie un tableau composé des mots compris dans entree séparés par le séparateur""" return [] # Programme-test string_mots_famille = '''parenté, filiation, familial, dynastie, généalogie, ménage, """ t = generer_tableau_des_mots(string_mots_famille, '\n') print(t)

...CORRECTION...

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
# Déclaration des fonctions def generer_tableau_des_mots(string_des_mots:str, separateur:str) -> list: """Renvoie un tableau composé des mots compris dans entree séparés par le séparateur""" mots_sans_virgule = string_des_mots.replace(',', '').lower() return mots_sans_virgule.split(separateur) # Programme-test string_mots_famille = '''parenté, filiation, familial, dynastie, généalogie, ménage, """ t = generer_tableau_des_mots(string_mots_famille, '\n') print(t)

Maintenant que nous savons créer un tableau contenant les mots qui nous intéresse pour surveiller un champ lexical, nous allons pouvoir créer un fonction evaluer_theme()

  • qui va recevoir
    1. le texte qu'on veut étudier et
    2. un tableau contenant les mots du champ lexical voulu
  • qui renvoie un compteur contenant le nombre de mots détéctés : la fonction va chercher tous les mots du thème et incrémenter un compteur dès qu'elle trouve ce mot !

2 - Evaluer un thème

Nous allons donc maintenant utiliser les deux fonctions basiques précédentes (detecter_le_mot() et generer_tableau_des_mots()) pour réaliser une tâche plus complexe : détecter automatiquement tous les mots du thème qui apparaissent dans le texte étudié.

Pour alléger un peu les choses, nous allons commencer par créer trois fichiers Python qu'il faudra placer dans un même dossier. De cette faàon, nous pourrons utiliser le principe des adresses relatives.

📁 dossier_de_votre_activite

📄 texte.py (question 13)

📄 mots.py (question 14)

📄 projet.py (question 15)

13° Créer le script Python texte.py en utilisant les lignes ci-dessous.

Attention au nom du fichier et à sa localisation !

Il faudra y placer le texte que vous voulez étudier.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
# Partie Déclaration des CONSTANTES TEXTE = """ Dites-moi d'où il vient Enfin je saurai où je vais Maman dit que lorsqu'on cherche bien On finit toujours par trouver Elle dit qu'il n'est jamais très loin Qu'il part très souvent travailler Maman dit "Travailler c'est bien" Bien mieux qu'être mal accompagné! Pas vrai? Où est ton papa? Dis-moi, où est ton papa? Sans même devoir lui parler Il sait ce qu'il ne va pas Un sacré papa Dis-moi où es-tu caché? Ça doit faire au moins mille fois Que j'ai compté mes doigts Où t'es? Papa où t'es? Où t'es? Papa où t'es? Où t'es? Papa où t'es? Où t'es? Où t'es? Où Papa où t'es? Où t'es? Papa où t'es? Où t'es? Papa où t'es? Où t'es? Papa où t'es? Où t'es? Où t'es? Où Papa où t'es? Où t'es? Quoi, qu'on y croit ou pas Il y aura bien un jour où on n'y croira plus Un jour où l'autre on sera tous papa Et d'un jour à l'autre, on aura disparu Serons-nous détestables? Serons-nous admirables? Des géniteurs ou des génies Dites-nous qui donne naissance aux irresponsables? Ah, dites-nous qui, tiens Tout le monde sait comment on fait des bébés Mais personne ne sait comment on fait des papas Monsieur je sais tout en aurait hérité, c'est ça? Il faut le sucer de son pouce où quoi? Dites-nous où c'est caché? Ça doit faire au moins mille fois Qu'on a bouffé nos doigts Où t'es? Papa où t'es? Où t'es? Papa où t'es? Où t'es? Papa où t'es? Où t'es? Où t'es? Où Papa où t'es? Où t'es? Papa où t'es? Où t'es? Papa où t'es? Où t'es? Papa où t'es? Où t'es? Où t'es? Où Papa où t'es? Où t'es? Où est ton papa? Dis-moi, où est ton papa? Sans même devoir lui parler Il sait ce qu'il ne va pas Un sacré papa Dis-moi où es-tu caché? Ça doit faire au moins mille fois Que j'ai compté mes doigts Où est ton papa? Dis-moi, où est ton papa? Sans même devoir lui parler Il sait ce qu'il ne va pas Un sacré papa Dis-moi où es-tu caché? Ça doit faire au moins mille fois Que j'ai compté mes doigts Où t'es? Papa où t'es? Où t'es? Papa où t'es? Où t'es? Papa où t'es? Où t'es? Où t'es? Où Papa où t'es? Où t'es? Papa où t'es? Où t'es? Papa où t'es? Où t'es? Papa où t'es? Où t'es? Où t'es? Où Papa où t'es? Où t'es? """

14° Télécharger le fichier mots.py. Le placer dans le même dossier que le fichier précédent.

15° Créer le script Python projet.py en utilisant les lignes ci-dessous.

Attention au nom du fichier et à sa localisation !

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
# Partie 1 - Importation from texte import TEXTE from mots import MOTS_FAMILLE from mots import MOTS_AMOUR from mots import MOTS_MORT from mots import MOTS_SCIENCE from mots import MOTS_ECONOMIE # Partie 2 - DECLARATION DES CONSTANTES # Partie 3 - DECLARATION DES FONCTIONS def detecter_le_mot(mot:str, string:str) -> int: """Renvoie 1 si on détecte la présence du mot dans le string fourni, 0 sinon""" reponse = 0 if mot in string: reponse = 1 return reponse def generer_tableau_des_mots(string_des_mots:str, separateur:str) -> list: """Renvoie un tableau composé des mots compris dans entree séparés par le séparateur""" temporaire = string_des_mots.replace(',', '').lower() return temporaire.split(separateur) def evaluer_theme(mots_cherches:list, texte:str) -> int: """Renvoie le nombre de mots présents dans mots_cherches qui apparaissent dans texte""" pass # Partie 4 - PROGRAMME PRINCIPAL t_famille = generer_tableau_des_mots(MOTS_FAMILLE, "\n")

Questions

  1. Que contient t_famille si vous l'évaluez dans la console après avoir lancé ce programme ?
  2. Au début du programme (lignes 3 à 8), dans quelles CONSTANTES sont contenues les strings contenant les mots ? Avec quel mot-clé demande-t-on d'aller les chercher dans un autre fichier Python ?
  3. Sur quelle ligne transforme-t-on le string des mots associés à la famille en tableau de mots ?

...CORRECTION...

  1. Que contient t_famille si vous l'évaluez dans la console après avoir lancé ce programme ?
  2. La variable contient bien la liste des mots associés à ce thème.

  3. Dans quoi sont contenus les strings contenant les mots ? Avec quel mot-clé demande-t-on d'aller les chercher dans un autre fichier Python ?
  4. Dans les constantes nommés MOTS_.... Les strings ne sont d'ailleurs pas contenus dans le fichier lui-même mais dans le script nommé mot.py. On notera d'ailleurs qu'on ne place pas le .py puisqu'il doit s'agir d'un script Python. On note juste mot

    Pour importer des choses depuis d'autres scripts, on utilise le mot-clé import.

  5. Sur quelle ligne transforme-t-on le string des mots associés à la famille en tableau de mots ?
  6. 33
    t_famille = generer_tableau_des_mots(MOTS_FAMILLE, "\n")

Maintenant, vous avez un projet fonctionnel séparé en trois fichiers

  1. Un script contenant le texte qu'on veut étudier.
  2. Un script contenant les mots des champs lexicaux à surveiller.
  3. Un script qui contient notre programme lui-même.

16° Réaliser (à partir de la ligne 26 et plus du script projet.py) la fonction evaluer_theme() dont voici le prototype :

26
def evaluer_theme(mots_cherches:list, texte:str) -> int:

Cette fonction devra :

  1. Convertir le texte reçu en minuscules et placer cette nouvelle version dans texte
  2. Créer un compteur nb_detection qui permettra de comptabiliser le nombre de mots cherchés détectés dans le texte (n'oubliez pas qu'à chaque fois qu'on crée un compteur, il faut l'initialiser à 0, l'ordinateur ne peut pas le faire de lui-même)
  3. Pour chaque indice i disponible dans le tableau mots_cherches
    • Incrementer le compteur nb_detection en utilisant la réponse de la fonction detecter_le_mot() sur le mot contenu dans la case i de mots_cherches : mots_cherches[i].
  4. Répondre en renvoyant le compteur nb_mots

Voici un exemple d'utilisation sur la chanson de Stromae :

>>> evaluer_theme(t_famille, TEXTE) 6

...CORRECTION...

1 2 3 4 5 6 7
def evaluer_theme(mots_cherches:list, texte:str) -> int: """Renvoie le nombre de mots présents dans mots_cherches qui apparaissent dans texte""" texte = texte.lower() nb_detection = 0 for i in range( len(mots_cherches) ): nb_detection = nb_detection + detecter_le_mot(mots_cherches[i], texte) return nb_detection

17° Nous avons tester le champ lexical de la famille avec l'appel précédent. Réaliser maintenant les appels nécessaires à la fonction evaluer_theme de façon à parvenir à évaluer les champs lexicaux de l'amour, de la guerre, de la science et de l'économie. Parvenons nous à percevoir les thèmes principaux de la chanson de Stromae 

...CORRECTION...

>>> evaluer_theme(t_famille, TEXTE) 6 >>> evaluer_theme(t_amour, TEXTE) 1 >>> evaluer_theme(t_mort, TEXTE) 4 >>> evaluer_theme(t_science, TEXTE) 3 >>> evaluer_theme(t_economie, TEXTE) 1

Les appels permettent de voir que le thème de la famille et le thème de la mort sont les deux thèmes les plus marqués. Au final, sa chanson parle bien de la cela : de la famille et de la mort de son espoir d'avoir ses deux parents.

Le programme n'est bien entendu par très performant pour le moment :

  1. Il ne gère que 5 thèmes
  2. Les mots n'ont pas du tout été vérifiés : certains mots sont présents dans certains champs lexicaux sans qu'on sache vraiment pourquoi...
  3. Rien n'empêche que certains mots de thème soient présents deux fois, ou trois... Cela pourrait fausser les résultats.
  4. On vérifie juste que la chaîne est présente : "vert" va être detecté si on rencontre le mot "vertical" dans le texte étudié.

Bref, ce n'est pas parfait. Une réalisation plus propre pourrait être l'occasion d'un vrai projet en autonomie.

18° Récupérer un article ou le texte d'un roman et lancer le programme sur votre texte. On faudra bien entendu remplacer le contenu de la constante TEXTE du fichier texte.py par votre propre texte.

A titre d'exemple, j'ai lancé le programme sur un article du CRNS parlant de la première "photo" d'un trou noir.

Image du trou noir
Représentation du trou noir par l'IA

Voici le texte tiré du site précédent qu'on pourrait placer dans le script :

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
TEXTE = '''Ce résultat historique fait partie du TOP 10 des plus consultés sur notre site cette année ! En avril dernier, les scientifiques de la collaboration Event Horizon Telescope révélaient la première image d’un trou noir, celui niché au cœur de la Galaxie M87. Relisez notre reportage en Espagne, au pied du radiotélescope de 30 mètres de l’Iram qui a contribué à cette prouesse. Le groupe est resté à l’extérieur pour profiter du paysage. Et malgré le froid qui traverse les tenues les plus légères, nul n’a regretté ce choix. Au loin, les contreforts partiellement enneigés de la Sierra Nevada dessinent sur le bleu azur du ciel espagnol les contours d’un escalier dont les marches descendent jusqu’à une plaine brumeuse occupée par la ville de Grenade. Juste devant, cachant de sa structure massive et blanche une large fraction de l’horizon, une énorme antenne interroge d’un œil suspicieux les mystères du Cosmos… « Voici, le télescope de 30 mètres de l’Iram qui a contribué à réaliser la toute première image d’un trou noir », annonce fièrement Frédéric Gueth, chargé de recherche CNRS et directeur adjoint de l’Institut de radioastronomie millimétrique (Iram) en se dirigeant vers une porte du bâtiment placé au pied de ce dispositif de géant. C’est en effet ici, à 2 850 mètres d’altitude, sur les pentes du Pico Veleta, en Andalousie, dans le sud de l’Espagne que fut recueillie en avril 2017, une partie des quatre pétaoctets (1015 octets) de données ayant servi à l’élaboration de l’extraordinaire cliché dévoilé aujourd’hui par la collaboration internationale Event Horizon Telescope (EHT). Ce dernier montre un anneau brillant entourant une région circulaire sombre : rien de moins que l’ombre de M87*, trou noir supermassif du centre de la Galaxie M87 ! Pour comprendre la portée d’une telle observation, il faut remonter le temps sur plus d’un siècle, jusqu’à l’année 1915, date de la découverte de la théorie de la relativité générale d’Albert Einstein. Celle-ci démontre pour la première fois que des corps aussi massifs que des étoiles peuvent, dans certaines conditions, s’effondrer sous l’effet de leur propre gravité jusqu’à former une région de l’Espace dont plus rien, ni la matière, ni la lumière ne peuvent sortir : un trou noir. Contrairement à ce qui a d’abord été cru, un tel objet ne se réduit pas à un point ou à une singularité perdue dans l’immensité du Cosmos. Il est délimité par une frontière intangible et invisible appelée horizon des événements, au-delà de laquelle rien ne peut revenir. Relativité générale confirmée C’est l’existence de cet horizon des événements associée aux trous noirs que démontre l’image diffusée par la collaboration EHT. La découverte qui fait l’objet de six articles dans la revue Astrophysical Journal Letters, confirme aussi, pour la première fois de manière directe, la validité des équations de la relativité générale d’Albert Einstein dans un régime de forts champs de gravité. Mais avant d’en arriver là, bien des efforts ont été nécessaires. En effet, explique Frédéric Gueth en pénétrant dans la salle de contrôle où des écrans pilotent la titanesque machine, fonctionnant dans le domaine des ondes millimétriques : « Projeté sur la voûte céleste, un horizon des événements a l’aspect d’un disque parfaitement noir, plus ou moins aplati. » Tel quel, exception faite peut-être d’une forme de radiation particulière théorisée par le physicien Stephen Hawking, il ne serait pas repérable par des télescopes. Rayonnement intense « Heureusement, les trous noirs sont rarement des astres isolés. Ceux repérés au centre des Galaxies occupent des régions riches en étoiles, en poussières et en gaz », précise le chercheur. Cette matière en orbite autour de ces objets cosmiques forme un disque d’accrétion dont l’échauffement produit un rayonnement intense caractéristique. Toutefois, elle devient invisible, dès lors qu’arrachée à cette structure annulaire, elle franchit la limite de l’horizon des événements. Créant au bout du compte une région sombre sur un fond brillant : l’ombre du trou noir. L’image que renvoie un tel objet vers un observateur lointain, n’a cependant rien d’intuitif. Dès 1979, Jean-Pierre Luminet, alors jeune chercheur au CNRS, l’a modélisée (lire le communiqué à ce sujet) en prenant en compte les propriétés physiques de la matière soumises à ces conditions infernales et la façon dont la structure de l’espace-temps – notamment la trajectoire des rayons lumineux qui la traversent – est affectée par la gravité du trou noir. Le cliché diffusé par l’équipe du EHT montre l’ombre de M87* vue sous un angle d’inclinaison du disque d’environ 60° avec ce dernier tournant dans le sens des aiguilles d’une montre. On y distingue dans le halo lumineux entourant la région sombre centrale, une zone plus brillante sur un seul côté. Cette dernière est caractéristique d’une image déformée par la présence du trou noir. Problème de taille Autre problème qu’ont dû surmonter les scientifiques : la taille. En effet, l’horizon des événements d’un trou noir ne délimite qu’un minuscule volume d’espace. Une sphère de quelques dizaines de kilomètres de diamètre à peine lorsque ce dernier est issu d’une simple étoile massive. Conséquence, poursuit Frédéric Gueth : « Avec les moyens actuels, les astronomes ne peuvent espérer observer que les trous noirs supermassifs les plus proches. » Et ils ne disposent pour cela que de deux cibles potentielles : Sagittarius A* (en abrégé SgrA*), l’objet de 4,14 millions de masse solaire qui occupe le centre de la Voie lactée à 26 000 années-lumière de la Terre. Et M87*, géant de 6,5 milliards de masse solaire, placé au cœur de la Galaxie elliptique Messier 87 (M87), dans la constellation de la Vierge. Mais, le défi n’en restait pas moins considérable. En effet, l’horizon des événements de M87* a un rayon compris entre 65 et 123 unités astronomiques – mais il s’agit de le discerner à 50 millions d’années-lumière de distance ! Même en profitant de l’effet de loupe dû aux lentilles gravitationnelles créé par la relativité générale, les astronomes doivent distinguer une ombre occupant sur la voûte céleste un angle inférieur à 25 micro-arc-secondes. Hors de portée des plus puissants télescopes ! Résolution haute précision D’où le projet EHT. Lancé en 2016 sous l’impulsion de Sheperd Doeleman et de Heino Falcke, respectivement astronome au MIT (États-Unis) et professeur à l’Université de Radboud (Pays-Bas), ce programme international, financé pour sa partie européenne via une bourse du Conseil européen de la recherche d'un montant de 14 millions d'euros, consiste à faire appel à une technique d’interférométrie à très longue base (VLBI1), rarement utilisée à une telle échelle et à de telles longueurs d’ondes (1,3 millimètre) afin de saisir les images des ombres de SgrA* et de M87*. « En effet, explique Frédéric Gueth, les poussières opaques présentes sur la ligne de visée de ces sources ne laissent passer la lumière qu’à ces fréquences. » En synchronisant avec une précision d’une fraction de millionième de seconde les instruments de huit – bientôt dix – observatoires répartis sur la surface du globe, puis en croisant les données récoltées, ces astronomes entendent produire des clichés d’une résolution équivalente à celle qu’aurait un unique radiotélescope de 10 000 kilomètres de diamètre. Une résolution de 26 micro-arc seconde, qui permettrait de lire, depuis New York, un journal déposé sur une table parisienne ! Images et modèles numériques C’est à cette expérience mondiale et inédite qu’ont participé les scientifiques du 30 mètres de l’Iram, Pico Veleta. Durant quatre jours, les 5, 6, 10 et 11 avril 2017, ce radiotélescope a, en coordination avec sept autres instruments placés aux États-Unis, à Hawaï, au Chili, au Mexique et en Antarctique – parmi lesquels l’interféromètre géant Alma2 –, dirigé son œil successivement vers Sgr A* et sur M87*. Un moment de stress pour l’équipe, car, comme le raconte Pablo Torne de l’Iram qui participait à l’aventure : « La technique n’avait jamais été employée dans ces conditions et il était impossible de savoir si l’on avait réussi. » La quantité de données recueillies au cours du test dépassant de loin, les capacités d’Internet, toute l’information fut emmagasinée sur des disques durs qui devaient être, acheminés plus tard jusqu’à des centres spécialisés placés à Haystack (États-Unis) et à Bonn (Allemagne). Cette opération ne fut achevée qu’à la fin du mois de décembre. Helge Rottman du Max-Planck-Institut für Radioastronomie (MPIfR) se souvient avoir vécu un « instant de grande excitation » lorsque, enfin, à la veille de Noël, le dernier paquet est arrivé à Bonn : « Il a fallu attendre six mois qu’un hélicoptère soit disponible pour aller récupérer, en Antarctique, les mémoires de stockage du Télescope du Pôle Sud (SPT3) ! » Une fois recombinés dans les puissants corrélateurs du Haystack Observatory, près de Boston et du MPIfR à Bonn, les signaux ont été confiés à quatre équipes qui ont travaillé de manière indépendante. Ces groupes ont procédé, chacun de leurs côtés, aux traitements adéquats pour en tirer, selon trois méthodes différentes, des images qu’il a fallu débarrasser de leurs artefacts et confronter aux modèles numériques. Un travail de bénédictin qui a abouti à cette visualisation inédite de M87* ainsi qu’à une estimation précise de la taille de son ombre (22 micro-arc-secondes) et de sa masse : entre 5,8 milliards et 7,2 milliards de fois la masse du Soleil, une valeur cohérente avec les estimations précédentes des astronomes. L’opération s’est toutefois soldée par un échec dans le cas de SgrA*, certes moins massif mais pourtant beaucoup plus proche. En effet, explique Frédéric Gueth : « Aux problèmes de calibration, s’est ajouté le constat que cette source est fluctuante et peut-être mal orientée par rapport à la Terre. » Que ce soit à cause des mouvements de matière dans le disque du trou noir ou d’un autre phénomène, les variations horaires de luminosité de l’ombre, brouillent les signaux. Un souci que les équipes espèrent résoudre en augmentant, lors des prochaines campagnes, la sensibilité du réseau EHT par l’ajout de nouvelles stations d’observation. L’une d’entre elles sera située en France. Il s’agit de l’interféromètre Noema de l’Iram dont les dix (et bientôt douze) antennes de 15 mètres installées à 2500 mètres d’altitude, sur le Plateau de Bure, dans les Hautes-Alpes, vont rentrer dans la danse. Avec un objectif : arracher aux trous noirs leurs ultimes secrets. """

Et voici le résultat de l'"analyse".

>>> evaluer_theme(t_famille, TEXTE) 17 >>> evaluer_theme(t_amour, TEXTE) 8 >>> evaluer_theme(t_mort, TEXTE) 17 >>> evaluer_theme(t_science, TEXTE) 26 >>> evaluer_theme(t_economie, TEXTE) 3

On voit bien qu'il s'agit d'un article scientifique.

A vous de jouer sur votre propre texte.

Tout cela est fortement perfectible. Pour l'instant, on peut donc estimer facilement le thème, la teneur général d'un texte.

Dans une autre activité, nous verrons comment parvenir à obtenir une sorte de résumé d'un texte en obtenant les mots qui apparaissent le plus.

Bref, vous l'avez compris : avec un bon algorithme, on peut assez facilement savoir de quoi vous parler et avec qui vous en parler.

3 - Tkinter

Partie optonnelle : aucune connaissance Tkinter attendue pour le BAC
Pour ceux qui ont le temps. L'utilisation d'une interface graphique n'est pas au programme de NSI.

Nous allons finir avec une petite application graphique Tkinter qui permet de réaliser une animation : une balle rebondit sur les parois.

S'agissant d'un dessin qu'on modifie rapidement à l'écran pour donner l'illusion d'un déplacement, le programme crée plusieurs éléments :

  • Ligne 78 : la fenêtre de l'application (de type Tk)
  • 78
    fenetre = creation_interface("Balle balle", "#8844BB")
  • Ligne 81 : un nouveau widget (de type Canvas) qui est simplement une zone dans laquelle nous allons pouvoir dessiner des choses
  • 81
    canvas = tk.Canvas(fenetre, bg="dark grey", height=300, width=300, borderwidth=0, highlightthickness=0)
  • Ligne 88 : un dessin rond dont la variable numero_mobile n'est rien d'autres que le numéro du dessin dans le Canvas précédent. Pour le créer, on doit donner les deux coordonnées x1, y1 du point en haut à gauche et les deux coordonnées x2, y2 du point en bas à droite. Comme on décale de 20 pixels à chaque fois, on obtient un rond et pas une forme ovale.
  • 88
    numero_mobile = canvas.create_oval(xo, yo, xo+20, yo+20, width=1, fill="yellow")

TK 01° Mettre le programme en mémoire pour vérifier qu'il fonctionne à peu près : la balle rebondit bien mais pas sur les parois. Pour activer le déplacement, il faut appuyer sur les flèches gauche ou droite de votre clavier.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
# - 1 - importation des modules nécessaires import tkinter as tk import random as rd # - 2 - variables globales DPCT = 3 # - 3 - Déclaration des fonctions def creation_interface(titre, couleur): """Crée et renvoie la référence d'interface graphique :: param titre(str) :: le titre visible dans la barre de l'application :: param couleur(str) :: une couleur de fond valide pour l'application :: return (tk.Tk) :: la référence Tkinter de l'application """ fe = tk.Tk() fe.geometry("350x350") fe.title(titre) fe.configure(bg=couleur) return fe def activer_gestion_evenements(): """!activation des surveillances des flèches gauche et droite""" fenetre.bind('<Right>', lancement_droite) fenetre.bind('<Left>', lancement_gauche) def stopper_gestion_evenements(): """Annule l'activation des surveillances des flèches gauche et droite""" fenetre.unbind('<Right>') fenetre.unbind('<Left>') def lancement_droite(e): """Fonction évenementielle qui lance juste droite()""" stopper_gestion_evenements() droite() def lancement_gauche(e): """Fonction évenementielle qui lance juste gauche()""" stopper_gestion_evenements() gauche() def droite(): """Fait avancer le mobile de DPCT pixels vers la droite""" canvas.move(numero_mobile, DPCT, 0) canvas.update() if coordonnee_horizontale(numero_mobile, canvas) <= 190: fenetre.after(50, droite) else: fenetre.after(50, gauche) def gauche(): """Fait avancer le mobile de DPCT pixels vers la gauche""" canvas.move(numero_mobile, -DPCT, 0) if coordonnee_horizontale(numero_mobile, canvas) >= 110: fenetre.after(50, gauche) else: fenetre.after(50, droite) def coordonnee_horizontale(n, c): """Renvoie l'abscisse du centre du mobile de numéro n dans le canvas c :: param n(int) :: numéro du dessin à étudier :: param c(Canvas) :: référence du Canvas dans lequel le dessin est présent :: return (int) :: la coordonnée x voulue """ return (c.coords(n)[0] + c.coords(n)[2]) // 2 # - 4 - Programme principal # - 4.1 - Création de la fenêtre du logiciel fenetre = creation_interface("Balle balle", "#8844BB") # - 4.2 - Création du Canvas zone_dessin, la zone de déplacement du mobile canvas = tk.Canvas(fenetre, bg="dark grey", height=300, width=300, borderwidth=0, highlightthickness=0) canvas.place(x=25, y=25) # - 4.3 - Création du mobile qu'on va déplacer sur le Canvas xo = rd.randint(100,200) yo = rd.randint(100,200) numero_mobile = canvas.create_oval(xo, yo, xo+20, yo+20, width=1, fill="yellow") # - 4.4 - Création des événéments activer_gestion_evenements() # - 4.5 - Surveillance de l'application fenetre.mainloop() # Surveillance des événements sur la fenêtre

Questions

  1. Sur quelles lignes sont crées les liaisons entre les événement Flèche Droite et Flèche Gauche aux fonctions évenementielles lancement_gauche() et lancement_droite() ?
  2. A quoi voit-on que les fonctions lancement_gauche() et lancement_droite() sont des fonctions événementielles ?
  3. Que provoque les instructions de lancement_droite() ?

...CORRECTION...

  1. LIGNE 92 : on lance la fonction activer_gestion_evenements() et on arrive LIGNES 28 et 29 :
  2. 26 27 28 29
    def activer_gestion_evenements(): """!activation des surveillances des flèches gauche et droite""" fenetre.bind('<Right>', lancement_droite) fenetre.bind('<Left>', lancement_gauche)
  3. Ces deux fonctions possèdent un paramètre (nommé ici e) qui sera rempli automatiquement avec les informations sur l'événément qui a provoqué son activation.
  4. Il suffit de lire les instructions de la fonction :
    • Ligne 38 : on active la fonction stopper_gestion_evenements() qui désactive la surveillance des touches gauche et droite avec la méthode unbind() (cela évite de pouvoir "démarrer" plusieurs fois l'animation).
    • Ligne 39 : on lance la fonction droite()

Pour comprendre l'animation, il faut étudier les fonctions gauche() et droite() et savoir ce que réalisent les méthodes qu'on y trouve :

  • la méthode move()
  • la méthode update()
  • la méthode after()
46 47 48 49 50 51 52 53
def droite(): """Fait avancer le mobile de DPCT pixels vers la droite""" canvas.move(numero_mobile, DPCT, 0) canvas.update() if coordonnee_horizontale(numero_mobile, canvas) <= 190: fenetre.after(50, droite) else: fenetre.after(50, gauche)

Comment cela fonctionne ?

  • Ligne 48 : la méthode move() permet de déplacer l'un des dessins d'un canvas en x et en y. On doit donner le nom du canvas devant la méthode, puis, entre les parenthèses de la méthode, le numéro du dessin, le décalage en x en pixels et le décalage en y en pixels. On voit ici qu'on va donc déplacer le rond de DPCT pixels horizontalement et 0 pixels verticalement.
  • Ligne 49 : la méthode update() impose au canvas de mettre à jour son apparence. Il le fait régulièrement mais on force ici son changement d'apparence pour être certain que la modification soit prise en compte.
  • Ligne 50 : on teste la coordonnée x centrale du rond à l'aide de la fonction coordonnee_horizontale() dont je n'expliquerai pas le fonctionnement ici. Sachez juste qu'elle renvoie cette coordonnée lorsqu'on lui fournit le numéro d'un dessin et la référence du canvas. Si la coordonnée horizontale est inférieure à 190 pixels (on est pas encore trop à droite), on voit qu'on réactive la fonction droite() quelques millisecondes plus tard. Sinon, on active gauche() pour repartir vers la gauche.
  • Lignes 51 et 53 : la méthode after() demande de lancer une fonction dont on fournit l'adresse après un certain nombdre de millisecondes (50 ms ici). Rappel 50 ms = 50.10-3 s = 0.050 s.

TK 02° Expliquer comment fonctionne la fonction gauche().

Finalement, modifier la fonction de façon à ce que la balle fasse bien des aller-retours lorsqu'elle "percute" le bord du canvas.

4 - FAQ

Du coup, on peut tester le type des variables ?

Oui. Les deux manières de faire les plus courantes sont fournies ci-dessous :

Première méthode : tester le type de la variable.

>>> a = 5.0 >>> type(a) == float True >>> type(a) == int False >>> type(a) == str False >>> a = "5.0" >>> type(a) == float False >>> type(a) == int False >>> type(a) == str True

Deuxième façon de faire : utiliser la fonction native isinstance.

>>> a = 5 >>> isinstance(a, float) False >>> isinstance(a, int) True >>> isinstance(a, str) False

Les tests conditionnels, les boucles bornées FOR.

Il nous reste à associer ces deux notions et voir la boucle non bornée : la boucle TANT QUE que va réaliser le travail demandé TANT QUE la condition proposée est évaluée à VRAI.

Activité publiée le 13 11 2021
Dernière modification : 04 10 2022
Auteur : ows. h.