<string>

Table des matières

Introduction

Introduction

Introduction

L'objectif des missions des cours d'informatique est de vous amener non pas à une maîtrise complète de la programmation en Python, y compris les aspects avancés (ce qui est visé pour la fin du baccalauréat), mais bien à un premier niveau qui vous permettra de résoudre des problèmes de programmation simple.

Chacun des problèmes possède des objectifs spécifiques plus détaillés, qui seront précisés dans les différents énoncés.

Notre intention est de vous faire prendre conscience du fait qu'il ne suffit pas de comprendre ou de connaître, il faut surtout être capable d'utiliser et de mettre en oeuvre toutes les connaissances acquises pour résoudre correctement de véritables problèmes. Pour le dire simplement: les connaissances que vous allez acquérir sont nécessaires, mais pas suffisantes.

Méthode pédagogique

Les problèmes d'informatique seront traités selon une variante de l'Apprentissage Par Problèmes (APP). Les buts principaux des problèmes d'informatique sont:

  • de vous inciter à acquérir les connaissances nécessaires,
  • de vous amener à pratiquer la mise en oeuvre de ces connaissances, seule manière d'apprendre à les exploiter correctement.

C'est en participant activement à la résolution des problèmes d'informatique que vous vous préparerez effectivement à l'évaluation finale (voir ci-dessous) et, en particulier, au volet mise en oeuvre des connaissances.

Dans cette méthode, le rôle du tuteur est de guider votre travail et votre apprentissage, pas de faire le travail à votre place ! Ne vous étonnez donc pas si le tuteur refuse parfois de répondre à vos questions: c'est sans aucun doute parce qu'il/elle estime qu'il vaut beaucoup mieux que vous cherchiez et trouviez les réponses par vous-mêmes.

Principes généraux

Les problèmes d'informatique sont traités selon une variante de l'Apprentissage Par Problèmes (APP) en une alternance de phases et de réunions en groupe :

Organisation d'un APP.

Le but poursuivi par cette organisation est de permettre à chacun d'entre vous d'atteindre les objectifs spécifiques énoncés pour le semestre et donc de vous préparer de manière efficace à réussir l'examen final. Chaque problème comporte un énoncé, qui présente le contexte du travail à effectuer sous la forme d'une mission à réaliser. A l'issue de chaque mission, chaque étudiant aura acquis de nouvelles connaissances et de nouvelles compétences; chaque groupe d'étudiants aura préparé une série de produits, qu'il aura remis au tuteur conformément aux indications fournies.

Se préparer

Le travail effectué pendant les phases (a) et (b) et pendant les réunions (A) et (B) a pour but

  • de vous rapprocher des objectifs d'apprentissage assignés au problème,
  • et de vous mettre dans les meilleures conditions possibles pour effectuer le travail de réalisation.

Comme le bon accomplissement de chaque mission exige des connaissances nouvelles, il est impossible d'effectuer correctement ces missions sans un travail de compréhension et d'apprentissage, dont une partie se fait avant la réalisation de la mission, une autre partie se fait pendant cette réalisation et une dernière partie se fait après la fin de la réalisation de la mission.

Réaliser une mission en négligeant le travail de compréhension et d'apprentissage ne permet pas d'atteindre les objectifs assignés au problème: cela ne permet donc pas de se rapprocher des objectifs du cours et donc de l'année.

Réaliser

Le travail de réalisation (c) a un double but:

  • vous amener à consolider et à approfondir votre compréhension des concepts visés dans le problème,
  • vous mettre dans une situation dans laquelle vous devez fournir la preuve que vous êtes en mesure d'appliquer correctement ce que vous avez appris (si ce n'est pas le cas, cela vous amènera à améliorer votre compréhension en poursuivant votre étude).

Le travail de réalisation vous entraîne en vue d'acquérir des compétences qui font partie des objectifs de l'année et qui seront certainement évaluées à l'examen final, à savoir la capacité à écrire des (fragments de) programmes.

Analyser et conclure

Le travail effectué pendant la phase (d) et pendant les réunions (C) et (D) a pour but

  • de vous amener à évaluer votre capacité à appliquer correctement ce que vous avez appris,
  • de vous amener à examiner par vous-mêmes la qualité et l'efficacité de votre travail en groupe et à décider de mesures à prendre pour les améliorer,
  • de vous amener à examiner par vous-même la qualité et l'efficacité de votre travail personnel et à décider de mesures à prendre pour les améliorer,
  • de vous entraîner à répondre à des questions qui pourraient figurer dans l'examen final.

Le fait d'analyser son travail et d'en tirer des conclusions permet d'augmenter graduellement l'efficacité de ce travail et donc sa propre productivité. C'est nécessaire, parce que le niveau d'exigences monte tout au long de l'année.

Remarques importantes

  • Rappelez-vous que le but ultime de l'ensemble des problèmes que vous allez traiter, ce n'est pas simplement de fournir au tuteur tous les produits de chaque mission, mais bien que chacun d'entre vous soit préparé à réussir l'interrogation et l'examen final, ce qui prouvera que les objectifs ont été atteints !
  • Lors de chaque réunion de bilan intermédiaire (B), le tuteur vérifiera avec vous si votre connaissance de la matière est suffisante pour poursuivre la mission en abordant le travail de réalisation. Si ce n'est pas le cas, il s'attendra à ce que vous formuliez un plan pour rattraper votre retard.
  • Une attention particulière sera portée sur la qualité des produits fournis et des réponses apportées aux questions (plus que sur la quantité): la lisibilité, la rigueur et la précision sont essentielles. Si vous n'arrivez pas au bout du travail de réalisation (par manque de temps), dites-vous bien qu'il est plus important de faire convenablement une partie du travail de réalisation que la totalité du travail de manière bâclée. Voyez-vous quelle en est la raison ?
  • Chaque travail effectué, chaque produit remis doivent être vus comme une occasion de témoigner de ce qui a été appris.

Aspects pratiques

Pour chaque problème, vous vous répartirez en binômes de 2 étudiants, en variant la constitution des binômes de semaine en semaine. Si le groupe compte un nombre impair d'étudiants, un membre différent travaillera seul pour chaque problème.

La raison pour laquelle nous procédons par sous-groupes est que la rédaction et la mise au point de programmes ne peut se faire de manière efficace en groupes de 6, mais est souvent difficile (tout au moins au début) quand on le fait seul. Travailler à deux est une formule qui a montré qu'elle pouvait être efficace (le travail par deux est d'ailleurs un des principes de base d'une approche de la pratique de la programmation appelée XP - Extreme Programming). Le fait de changer d'équipier à chaque fois favorise une meilleure répartition du travail sur le quadrimestre. Attention cependant : la résolution des problèmes doit être l'occasion, pour chaque étudiant, d'apprendre toute la matière visée. Avec ce travail en sous-groupes, le nombre de produits fournis par le groupe pour chaque problème est trop élevé pour que votre tuteur soit en mesure de les examiner et de les corriger tous. Par conséquent, le tuteur choisira lui-même un certain nombre de produits sur lesquels il vous fera ses commentaires.

Site Web et messagerie

Toute l'information relative au cours et tous les documents dont vous avez besoin se trouvent sur les sites Moodle des cours LEPL1401 et LINFO1101

https://moodleucl.uclouvain.be

Consultez ces sites fréquemment, de même que votre messagerie UCL, accessible par votre bureau virtuel sur le portail de l'UCL.

A propos d'évaluation

Il y a deux types d'évaluations notées qui sont prévues dans le cadre du programme de cette année :

  • l'évaluation (interrogation) en cours de semestre - typiquement en semaine S7 - dont l'objectif principal est de vous donner des indications précises sur votre maîtrise de la matière à un moment précis de l'année;
  • l'évaluation finale (examen), après chaque semestre, qui fait le bilan de ce que vous avez appris pendant le semestre et qui vérifie surtout la capacité à mettre en oeuvre les connaissances acquises.

Comme indiqué plus haut, un des buts des problèmes est de vous entraîner à mettre en oeuvre les connaissances acquises. C'est en faisant honnêtement le travail prévu que l'on apprend à exploiter ses connaissances (ou que l'on découvre des faiblesses ou des lacunes).

Pour éviter que l'écriture des programmes ne devienne un but en soi au détriment de la qualité de l'apprentissage, certains des produits fournis pour chacun des problèmes pourront être évalués et notés pour fournir une rétroaction sur le travail fourni, mais ces notes n'interviendront pas dans la note du travail du cours.

Remerciements

Remerciements

Ce document n'aurait pas pu être écrit sans l'aide de nombreuses personnes.

Olivier Bonaventure, Sébastien Combéfis, Damien Leroy et Charles Pecheur ont développé le recueil d'exercices des cours LFSAB1401 Informatique 1 et LSINF1101 Introduction à la programmation, qui ont précédé nos cours et se basaient sur le langage Java. Le présent recueil est largement dérivé de leur travail.

Elie Milgrom et Yves Deville sont les premiers à avoir développé une formule d'apprentissage par problèmes appliquée au premier cours d'informatique donné aux étudiants ingénieurs civils à l'UCL. L'organisation globale du cours et plusieurs problèmes s'inspirent fortement de leur travail. Le cours d'informatique actuel leur doit énormément.

Chaque année, environ 600 étudiants encadrés par une vingtaine de tuteurs et assistants utilisent les APPs du cours d'informatique. Leurs questions, commentaires, remarques, difficultés ont nourri les différents problèmes en nous suggérant de nouvelles questions ou de nouvelles idées de problèmes. Parmi ceux-ci, Benoit Donnet, José Vander Meulen, Jean-Noel Monette et Grégory Detal nous ont donné des commentaires précieux. Maxime De Mol a aidé à la mise en pages.

Plusieurs étudiants ont activement contribué à l'infrastructure informatique utilisée pour ce cours. Bastien Bodart a écrit dans le cadre de son mémoire des suites de tests pour la plupart des missions du cours afin de fournir un feedback rapide aux tuteurs. Anthony Gégo et Guillaume Derval ont construit avec Pierre Reinbold et d'autres le système INGInious qui permet aux étudiants d'écrire du code pour résoudre des exercices et d'avoir un feedback rapide sur le bon fonctionnement de leur code. Durant les Open Weeks organisées chaque été depuis 2015, des équipes d'étudiants, sous la coordination de François Michel, ont développé de nombreux exercices, écrit des suites de tests et développé de nombreuses fonctionalités qui sont maintenant intégrées à INGInious.

<string>

<string>

Table des matières

Mission 1 - Mise en route

Mission 1 : mise en route

Mission 1 : mise en route

Introduction

Chacun d'entre vous possède une expérience qui lui est propre en ce qui concerne l'utilisation d'outils informatiques. Certains ont déjà écrit des programmes sur un ordinateur, tandis que d'autres ont à peine effleuré un clavier...

Pour pouvoir commencer à travailler en groupe pour ce cours d'informatique, il est nécessaire de combler quelque peu ce fossé et de vous mettre plus sur un pied d'égalité. Autrement, ce sont ceux qui ont le plus d'expérience qui mèneront les groupes et les plus novices auront moins l'occasion de participer, donc d'apprendre - ce qu'il faut absolument éviter. Nous avons donc organisé une mission de mise en route, que chacun de vous devra accomplir individuellement.

Deux principes importants

  1. Vous devez mener cette mission individuelle de front avec les autres activités de la semaine. A chacun d'entre vous de veiller à combiner travail de groupe et travail individuel, ainsi que travail dans les autres cours. Plus tard, vous devrez être en mesure de combiner encore plus d'activités en y consacrant le temps et les efforts nécessaires.
  2. Même si chacun d'entre vous doit avoir effectué la mission individuellement, il est utile que les membres du groupe s'entraident !

Pré-requis

Conditions à remplir pour pouvoir résoudre le problème :

Si certains d'entre vous ont des difficultés avec un ou plusieurs de ces pré-requis, il est indispensable que le groupe les résolve avant de commencer à travailler.

Objectifs

Chaque mission vise à atteindre des objectifs individuels liés à la compréhension de la matière et des objectifs collectifs liés au fonctionnement du groupe. Pour cette mission de mise en route, les objectifs sont les suivants :

Objectifs individuels

A l'issue de cette mise en route, chacun d'entre vous :

  • sera en mesure de dire quelques mots (sensés !) sur certains concepts sous-jacents à un programme Python simple (après une première prise de connaissance) :

    • langage de programmation, programme
    • fichier contenant un programme Python
    • commentaires
    • exécution d'un programme
    • variables
    • boucles, conditions
  • sera en mesure d'utiliser l'environnement de travail Thonny pour écrire et exécuter des programmes en Python

  • aura une première idée des différentes ressources mises à votre disposition

Objectifs collectifs

A l'issue de ce problème, le groupe tout entier :

  • aura montré sa capacité à travailler ensemble pour aider les membres qui ont des difficultés à les résoudre.

Préparation, étude et apprentissage

La matière relative à cette mission porte sur les sections suivantes du syllabus. Vous devez lire et comprendre ces parties du syllabus pour pouvoir mener à bien cette mission.

Questionnaire de démarrage

Durant chaque mission, vous devrez répondre à deux types de questions individuelles :

Binding Inginious

Si c'est la première fois que vous vous connectez, vous voyez pour le moment 'Please log in to see this exercise' à la place du premier exercice. Vous devez d'abord vous logger avec votre identifiant global en cliquant sur 'Log In' en haut à droite. Ensuite, suivez la marche à suivre pour lier votre compte Inginious à ce compte et complétez les exercices.

  1. Des questions à choix multiples.

    Ces questions sont accessibles depuis un serveur Internet. Ce serveur vous génère automatiquement un ensemble de réponses différent à chaque fois que vous vous y connectez. Cela vous permet de tester vos connaissances lors de la première lecture du livre, mais aussi plus tard lorsque vous préparez l’interrogation ou l’examen. Vous devez préparer ces questions à choix multiples individuellement avant la réunion de bilan intermédiaire.

    
            
            

    Les questions à choix multiples de cette semaine sont également accessibles en ligne depuis https://inginious.info.ucl.ac.be/course/LSINF1101-PYTHON/Session1_QCM

  2. Des questions ouvertes. Ces questions seront discutées oralement durant la réunion de bilan intermédiaire. Votre tuteur choisira plusieurs étudiants et ceux-ci devront présenter au tableau leur réponse à l’une de ces questions ouvertes. Préparez ces questions avant cette réunion:

Question 1

a, b et c sont des variables contenant des nombres entiers quelconques. Comment feriez-vous pour déterminer la médiane de ces trois nombres ? Pour rappel, la médiane d’un ensemble de nombres est la valeur m telle qu’il y a dans l’ensemble autant de valeurs qui sont supérieures ou égales à m que de valeurs inférieures ou égales à m.

 
 
 
 
 
 

Etapes d'une instruction conditionnelle:

  1. Identifier les différent cas possible

  2. Déterminer dans quel ordre les traiter

  3. Ecrire une condition if

    if condition_1 :
       # Instructions pour le cas 1 (considérez que la condition_1 est vraie)
    
  4. Ecrire une condition elif pour chaque autre cas que vous voulez traiter

    elif condition_x :
       # Instructions pour le cas x
    
  5. Ecrire une condition else, pour tous les cas non traités précédemment

    else :
       # Instructions pour tous les autres cas
    

Pour plus de détails sur les étapes, allez voir le catalogue : Instruction Conditionnelle .

Question 2

Sachant que print(x) permet d’afficher à l’écran la valeur stockée dans la variable x, comment feriez-vous pour afficher à l’écran la table de multiplication par 123 ?

 
 
 
 
 
 

Etapes d'une boucle while:

  1. Définir et initialiser les variables ;
  2. Déterminer la condition d’arrêt (ou de continuation)
  3. Écrire le corps de la boucle (mettre à jour la variable de contrôle jusqu’à la condition d’arrêt si nécessaire).

Pour plus de détails sur les étapes, allez voir le catalogue : Boucle While .

Question 3

Que se passe-t-il lors de l'exécution de la boucle suivante :

n = 1
i = 0
while n > 0:
    i=i+n
print(i)
 
 
 
 
 

Question 4

Sachant que les expressions a // b et a % b calculent respectivement la division et le reste de la division de l’entier stocké dans la variable a par l’entier stocké dans la variable b, pouvez-vous écrire un boucle qui affiche à l’écran en utilisant la commande print() les diviseurs entiers du nombre entier positif stocké dans la variable n.

 
 
 
 
 
 
Mission 1

Mission 1

Une des premières applications des ordinateurs (et même des calculateurs mécaniques, comme la machine de Babbage) a été de générer, de manière automatique et fiable, des tables numériques de fonctions mathématiques, comme les logarithmes ou les fonctions trigonométriques.

Une table de logarithmes.

Dans cette mission initiale, vous allez produire une table des carrés et des sommes des carrés :

1        1       1
2        4       5
3        9       14
4        16      30
5        25      55
6        36      91
7        49      140
8        64      204
9        81      285
10       100     385
  • Démarrez une session de travail à l'ordinateur avec votre nom d'utilisateur et votre mot de passe. Créez, si ce n'est déjà fait, un répertoire (dossier) info1 où vous placerez tout ce qui se rapporte à l'informatique pour BAC1.

    Si vous ne voyez pas comment faire, faites-vous aider. Vous pouvez, entre autres, utiliser un navigateur Web ("Web browser") pour consulter les documents accessibles sur le site Moodle du cours.

  • Inscrivez vous au site web du cours. Vous y trouverez, entre autres, un lien vers des ressources qui sont mises à votre disposition. Parmi ces ressources, il y a des modes d'emploi qui expliquent comment utiliser les logiciels mis à votre disposition sur vos postes de travail.

  • Inscrivez vous au cours sur INGINious (https://inginious.info.ucl.ac.be). Pour cela, allez sur INGInious, connectez-vous à l'aide de votre identifiant global UCL et inscrivez-vous au cours INFO1.

  • Faites démarrer l'environnement de développement Thonny, qui permet d'introduire, de modifier et d'exécuter des programmes Python.

    Thonny est installé sur toutes les machines de l'EPL. Nous ne supportons pas d'autre éditeur de programmes en Python. Si vous souhaitez installer Thonny sur votre ordinateur personnel, téléchargez-le sur https://thonny.org/.

  • Créez un nouveau fichier que vous baptiserez mise_en_route.py.

  • L'instruction print(a, "\t", b) permet d'afficher à l'écran la valeur des variables a et b, séparées par une tabulation (le caractère spécial "\t"). Ecrivez un programme qui affiche à l'écran les nombres, les carrés et la somme des carrés pour les nombres entiers de 1 à 10, comme dans l'exemple ci-dessus. Utilisez la fonction print(), une boucle while et une variable pour calculer la somme au fur et à mesure.

  • Testez votre programme pour en vérifier le bon fonctionnement. Pour cela, cliquez sur le bouton Run (triangle blanc). Les résultats s'affichent dans le panneau Shell en bas de la fenêtre.

  • Exécutez votre programme pas à pas pour observer son fonctionnement. Pour cela, affichez d'abord le panneau des variables (menu View > Variables). Ensuite cliquez sur le bouton Debug (scarabée) et progressez avec les trois boutons Step into, Step over et Step out (flèches jaunes). Familarisez-vous avec leur fonctionnement et observez les valeurs des variables.

  • La somme des carrés des nombres de 1 à n peut aussi se calculer par la formule n(n + 1)(2n + 1) ⁄ 6. Modifiez votre programme pour qu'il affiche les nombres calculés par cette formule dans une quatrième colonne. Si votre programme est correct, les troisième et quatrième colonnes doivent être identiques !

Remise de votre solution

A l'issue de cette mission préparatoire vous devez soumettre votre programme au serveur de soumissions de programmes du cours. Ce serveur de test sera utilisé pour toutes les missions et également pour des exercices complémentaires. Il est important que chacun d'entre vous sache l'utiliser.

Si vous n'avez pas réussi à terminer l'écriture du programme, expliquez vos problèmes dans un fichier README.TXT mais soumettez quand même votre programme au serveur car c'est via le serveur que votre tuteur recevra les programmes qu'il corrigera pour la séance de retour. Si vous avez réussi à terminer le programme correctement, le fichier README.txt doit contenir une documentation destinée aux utilisateurs de votre programme.

La soumission automatique des projets se déroule comme suit :

  • Cette première mission est individuelle, mais les prochaines missions sont à réaliser avec un binôme différent chaque semaine. Avant de soumettre chaque mission, vous devez d'abord indiquer dans vos fichiers avec qui vous avez travaillé.
  • Seul un membre du groupe a besoin d'effectuer la procédure et soumettre chaque fichier complété demandé pour avoir un feedback en séance.

        
        

Si vous remarquez une erreur après la soumission, vous pouvez resoumettre pour la corriger. Vous recevrez un feedback global de votre tuteur durant la réunion de bilan final. En cas de problème de soumission via le serveur, utilisez le forum Helpdesk sur le site du cours.

Challenge

Les étudiants qui ont résolu rapidement cette mission de mise en route sont invités à écrire un programme permettant de résoudre le problème suivant.

Considérons un programme utilisant cinq variables entières : a, b, c, d et e. Comment feriez-vous, en utilisant uniquement des if ...: ... else: ... pour calculer la médiane de ces cinq valeurs. Pour rappel, la médiane est la valeur qui est telle qu'il y a exactement deux valeurs inférieures à elle et deux valeurs supérieures à elle.

Questions complémentaires

Questions complémentaires

The method sum(list) returns the sum of the elements contained in list.

Example: the sum of [1,2,3] is 6

Note that your algorithm should be able to compute the sum even when the list list contains malicious elements (not numbers).









You want to use your computer to easily compute a polynomial with the following form: y = ax6 + bx2 + c. We give you the coefficients (stored in a, b and c) and the variable x and ask you to put the value of the polynomial at abscissa x inside a variable named y.

Note: there is a way to make this shortly in only one line of code.









En mathématiques, la factorielle d'un entier strictement positif x, noté x!`estleproduitdetouslesentiersstrictementpositifspluspetitsouégauxà``x`. La factorielle de 0 est 1. Calculez la factorielle d'un entier x et enregistrez la valeur calculée dans la variable result.

Exemples:

  • 5! = 5×4×3×2×1 = 120
  • 0! = 1









<string>

Table des matières

Mission 2 - Bases de programmation

Mission 2 : Bases de programmation

Mission 2 : Bases de programmation

Introduction

Depuis son apparition durant la seconde guerre mondiale, l'informatique n'a cessé de transformer profondément la société. La science et les différents domaines de l'ingénieur sont aujourd'hui de plus en plus dépendants de l'informatique pour des besoins de calcul ou de simulation notamment. Dans un rapport récent [1], plusieurs scientifiques ont mis en avant les liens de plus en plus forts entre l'informatique et les différentes disciplines scientifiques. Ils vont même jusqu'à prévoir l'émergence de nouvelles formes de "sciences" qui feront la synthèse entre les sciences ou les métiers traditionnels de l'ingénieur et l'informatique. Dès aujourd'hui, cette synthèse a créé de nouveaux domaines comme la bioinformatique qui fait le lien entre la biologie moléculaire et l'informatique, la climatologie dont les prédictions dépendent d'ordinateurs de plus en plus puissants, mais aussi les nanotechologies où les modélisations informatiques sont essentielles pour comprendre les interactions entre atomes et molécules ou la physique des particules où des équipements tels que le Large Hadron Collider (LHC) installé récemment au CERN à Genève produisent des quantités de mesure tellement gigantesques qu'il faut utiliser des milliers d'ordinateurs pour les traiter.

Si les ordinateurs sont tellement utiles pour résoudre des problèmes scientifiques ou d'ingénierie c'est grâce à leur puissance de calcul. Cette puissance de calcul est à deux niveaux : matériel et logiciel. Au niveau matériel, les processeurs utilisés dans les ordinateurs actuels sont capables d'effectuer très rapidement des additions, multiplications, divisions, soustractions et comparaisons de nombres réels.

Pour cette mission, vous devez écrire un programme Python qui permet de trouver les solutions entières à des équations du style :

xm + yn = zp

Vous constaterez que l'énoncé de cette mission est plutôt directif. Dans les problèmes suivants, la mission sera bien moins explicite et une partie du travail de préparation consistera à la préciser.

[1]Towards 2020 Science, disponible depuis http://research.microsoft.com/towards2020science/

Pré-requis

Conditions à remplir pour pouvoir résoudre le problème :

  • savoir effectuer son login,
  • s'y retrouver dans les icônes, les fenêtres, etc. de Linux sur un poste de travail,
  • savoir lancer un programme comme Thonny et soumettre son travail sur le serveur de correction,
  • connaître le maniement élémentaire de Thonny,
  • savoir utiliser le navigateur (browser) Internet,
  • se débrouiller en anglais.

Objectifs

A l'issue de cette mission, chacun d'entre vous :

  • sera en mesure de dire quelques mots sur certains concepts sous-jacents à un programme Python simple :

    • types de données
    • chaînes de caractères
    • opérations arithmétiques
    • opérations booléennes
    • appel de fonction
    • boucles for
  • sera en mesure d'utiliser l'environnement de travail Thonny pour traiter des programmes écrits en Python et de soumettre son travail au serveur de correction.

Préparation, étude et apprentissage

Vous devez lire et comprendre ces parties du syllabus pour pouvoir mener à bien cette mission :

Comment bien préparer la mission

  1. Avoir assisté au cours et avoir fait la liste des points abordés.
  2. Lire une première fois les sections du livre de référence et noter les points qui demandent éclaircissement.
  3. Repasser sur les sections du livre qui traitent des points demandant éclaircissement.
  4. Répondre le mieux possible aux questions du QCM et du Questionnaire de démarrage; en cas de besoin, revoir les sections pertinentes du livre et/ou en discuter avec d’autres membres du groupe.
  5. Confronter vos réponses à celles d’autres étudiants lors de la séance du bilan intermédiaire.
  6. S’il reste des points à éclaircir, en discuter avec les autres membres de votre groupe.

Rappelez-vous qu'il est impossible d'atteindre les objectifs visés par ce problème sans effectuer préalablement le travail d'étude individuel en consultant les sections du livre de référence.

Questionnaire de démarrage

Les questions qui figurent ci-dessous sont des exemples de questions que vous pourriez vous poser à la lecture de l'énoncé et des ressources qui s'y rapportent. Si vous avez convenablement fait ce qui était attendu de vous pendant la phase d'étude et d'apprentissage, vous devriez être en mesure de répondre sans difficulté à ces questions. Si ce n'est pas le cas, il est encore temps de rattraper votre retard (mais ne tardez pas trop !). Il ne faut en aucun cas commencer la phase de réalisation avant d'être en mesure de répondre à ce questionnaire.

Pour chaque question, indiquez toujours où vous avez trouvé les éléments de réponse (livre page ..., documents fournis, manuels en ligne, ...). Travaillez en deux temps:

  1. faites la liste des éléments de réponse (au brouillon, p. ex. sur la page de gauche)
  2. rédigez la réponse

Visez à fournir des réponses complètes, motivées et qui prouvent votre compréhension de la matière. Ne vous contentez pas de réponses superficielles.

  • la réponse est-elle correcte ? (pas d’affirmations erronées)
  • la réponse est-elle complète ? (rien d’important n’a été oublié)
  • la réponse est-elle claire ? (on la comprend dès la première lecture)
  • la réponse est-elle précise et les termes utilisés sont-ils adéquats ? (pas d’à peu près...)
  • la réponse témoigne-t-elle d’une réelle compréhension/connaissance de la matière ? (la réponse ne donne pas l’impression que les auteurs se sont débarrassés de la question le plus rapidement possible)
  • la réponse est-elle bien rédigée ? (structure, style, orthographe)

Pour vous aider dans la réalisations de ces exercices, certains d'entre eux sont disponibles sur Inginious avec une correction automatisée. Il a été fait en sorte que cette correction automatique soit utile à votre compréhension de la matière, cependant cela ne doit pas vous empêcher de discuter de vos réponses, correctes ou non, avec votre tuteur et les membres de votre groupe.

Questions à choix multiple


        
        

Question 1

Définissez les concepts suivants :

  • variable
 
 

  • valeur
 
 

  • data type
 
 

  • instruction
 
 

  • expression
 
 

Question 2

Dans l'extrait de programme ci-dessous, indiquez après chaque ligne les valeurs contenues dans les variables a, b, c.

a = 0
b = 1
c = 2

a = b       # ligne 1
a = a*2     # ligne 2
b = 17      # ligne 3
c = a+b     # ligne 4
a = b-c     # ligne 5
c = a+b+c+a # ligne 6

Question 3

Expliquez, avec vos propres mots, ce que représente la notation

i = i + 1

et ce qu'elle a comme effet. Pourrait-on la remplacer par une autre notation ?

 
 
 
 

Question 4

Quelle est la relation entre une instruction et une expression ? Donnez des exemples.

 
 
 
 

Question 5

Expliquez ce que produisent les instructions suivantes :

  • print( 10 + 10 )
  • print( "10" + "10" )
  • print( int("10") + int("10") )
 
 
 
 

Question 6

Que se passe-t-il si on exécute ce programme ? Comment peut-on le corriger ?

n = input("n = ? ")
print("n^2 =", n ** 2)
 
 
 
 

Question 7

Expliquez ce que produisent les instructions suivantes :

  • print(10 / 3)
  • print(10 // 3)
  • print(10 % 3)
 
 
 
 

Question 8

Que fait le programme suivant ?

for n in [0, 1, 2, 3, 4]:
    print(10 ** n)

Comment pourrait-on écrire autrement la boucle for ?

 
 
 
 

Question 9

Complétez le fragment de code suivant:

# Place dans sum la somme des n premiers entiers pairs strictement positifs

n = some_value
sum = 0
for ___ in ___________:
    ______________

Etape d'une boucle for :

  1. Déterminer la séquence à parcourir entre des indices, éléments et une intervale
  2. Exprimer la condition de traitement avec une instruction conditionnelle if, si nécessaire.
  3. Écrire le corps de la boucle
  4. Vérifier les cas particuliers (liste vide, bornes de début et fin de parcours).

Pour plus de détails sur les étapes, allez voir le catalogue .







Question 10

Un nombre premier est un nombre naturel plus grand que 1 et qui n'a pas d'autres diviseurs positifis à part 1 et lui-même.

Stockez dans is_prime True si le n est un nombre premier et False sinon. is_prime est initialisé à True par défaut.

Les variables ont été initialisées. Ils vous restent à déterminer la séquence, écrire la condition de traitement si nécéssaire, le corps de la boucle et vérifier les cas particulier. Pour plus de détails sur les étapes, allez voir le catalogue .

is_prime = True
n = ...             #Un entier supérieur à 1







Mission 2

Mission 2

Remarques importantes

On ne commence ce travail de réalisation qu'après la réunion du bilan intermédiaire et en ayant déjà fait un premier travail d'étude dans le livre de référence.

Chaque étudiant dispose, sur le système informatique de l'EPL, d'un espace de travail qui lui est propre et auquel il accède en démarrant une session par un login sur n'importe lequel des postes de travail (en salles Candix/IAO/DAO). Les fichiers créés ou modifiés par un étudiant ne sont donc pas directement accessibles à un autre étudiant (il n'y a pas de partage de fichiers entre étudiants). Une manière simple d'échanger des fichiers entre étudiants d'un sous-groupe consiste à se les envoyer en annexe ("attachment") à un courrier électronique.

Durant cette partie de la mission vous allez écrire un petit programme Python permettant de rechercher les racines entières d'une équation diophantienne :

xa + yb = zc

Cette recherche se fera en énumérant toutes les valeurs possibles de x, y et z et en vérifiant pour chacun triplet de valeurs si l'équation diophantienne est vérifiée (attention, vous ne pouvez pas utiliser les fonctions du package math dans cette mission). Cette technique d'énumération est parfois utilisée dans le domaine de la sécurité informatique pour décoder des messages cryptés sans connaître la clé de cryptage qui a été utilisée. Elle s'appelle attaque par force brute ou recherche exhaustive.

  • Groupes : A partir de cette deuxième mission, vous travaillerez en binômes de deux étudiants. Associez-vous en binômes au sein de votre groupe ou de votre local. Si vous êtes en nombre impair dans votre local, un étudiant devra travailler seul. Vous devrez travailler avec un étudiant différent chaque semaine; organisez une tournante des binômes.

  • Organisation : Décidez comment vous allez faire, dans votre sous-groupe, pour travailler à deux : est-ce toujours le même qui travaille à l'ordinateur ou allez-vous alterner au milieu de la mission ? Que fait celui qui n'est pas à l'ordinateur pour aider celui qui l'est ? A quel moment faut-il aller consulter le livre de référence ? Faut-il avoir lu toutes les sections du livre indiquées dans la rubrique Ressources avant de faire le travail ?

  • Analyse : Considérez le programme ci-dessous :

    # Recherche des racines d'une équation a x + b y = c
    # Charles Pecheur, septembre 2018
    
    solutions = 0
    a = int(input("Entrez la valeur du coefficient a : "))
    b = int(input("Entrez la valeur du coefficient b : "))
    c = int(input("Entrez la valeur du coefficient c : "))
    max = int(input("Entrez la valeur maximale pour x et y : "))
    
    for x in range(1, max+1):
        for y in range(1, max+1):
            if a*x + b*y == c:
                print("x =", x, " y =", y)
                solutions += 1
    
    if solutions == 0:
        print("Aucune solution trouvee")
    else:
        print(solutions, "solutions trouvees")
    

    Ce programme recherche les racines entières de l'équation diophantienne simple ax + by = c. Essayez de le lire et de bien comprendre comment il fonctionne. Dans Thonny, recopiez le programme dans un fichier equation_simple.py (copiez-collez à partir du syllabus) et testez-le en l'exécutant avec différentes valeurs de a, b et c. Vérifiez notamment que l'équation 8 x + 4 y = 1 n'admet aucune solution alors que l'équation 2 x + y = 3 en admet une infinité.

    Vous pouvez inspecter les valeurs des différentes variables en affichant le panneau des variables (menu View > Variables) et en exécutant le programme pas à pas (bouton Debug). Attention, vous devez interrompre votre programme en cours d'exécution (bouton Stop) avant de pouvoir lancer une nouvelle exécution.

  • Vous pouvez maintenant créer un nouveau programme equation.py permettant de trouver des solutions à des équations diophantiennes du type xa + yb = zc.

    • Recherchez les racines d'une équation particulière. Prenons comme exemple x3 + y2 = z9.
    • Généralisez votre programme de façon à ce que par exemple l'utilisateur puisse, en utilisant la fonction input(), entrer la valeur de l'exposant de z. Utilisez z ** c pour calculer la valeur de zc. Vérifiez que votre programme permet de retrouver les racines de x3 + y2 = z9, c'est-à-dire 7, 13 et 2.
    • Continuez à généraliser votre programme en permettant à l'utilisateur d'entrer au clavier les valeurs des exposants de x, y et z.
    • Testez votre programme avec différents exposants. Vous trouverez sur Internet des solutions pour de nombreuses équations de ce type [1] et par exemple :
      • x7 + y3 = z2
      • x5 + y4 = z2
      • x3 + y2 = z7

    Si vous n'obtenez pas le bon résultat, analysez ce qui se passe et corrigez jusqu'à obtention du résultat désiré. Cette phase de test est essentielle dans le développement d'un programme. Indiquez dans le fichier README.TXT que vous renverrez à votre tuteur les tests que vous avez réalisés pour le convaincre du bon fonctionnement de votre programme.

    N'oubliez pas de bien documenter votre programme en utilisant des commentaires.

  • Si vous avancez vite, modifiez votre programme de façon à ce qu'il n'affiche que les racines qui n'ont aucun diviseur commun à l'exception de 1. Pour cela, vous devrez écrire un programme permettant de vérifier si trois nombres ont un diviseur commun. En Python, l'expression a % b calcule le reste de la division euclidienne de a par b. Cela pourrait vous aider dans cette extension.

Soumettez votre travail au serveur de soumission. Indiquez dans le fichier README.TXT les tests que vous avez effectués et les problèmes éventuels que vous avez eu. Votre tuteur pourra les lire afin de préparer la réunion de bilan final.

[1]Voir notamment http://www.alpertron.com.ar/SUMPOWER.HTM

Remise de votre solution

Pour cette mission, vous devez soumettre votre programme equation.py et votre fichier README.txt au serveur de soumissions de programmes du cours.

  • Au moins un étudiant du binôme doit ensuite soumettre les deux fichiers dans le panneau ci-dessous. Si vous remarquez une erreur après la soumission, vous pouvez resoumettre pour la corriger.

        
        

Challenge

Les étudiants qui ont résolu rapidement ce problème sont invités à écrire un programme permettant de résoudre le problème suivant.

En mathématiques, depuis les travaux de Fermat, on sait qu'il n'existe pas de quadruplet de nombres entiers positifs distincts a, b, c et n tels que an + bn = cn lorsque n > 2. Le théorème correspondant a d'ailleurs été démontré il y a seulement quelques années. Par contre, il existe de nombreux quadruplets de nombres entiers positifs distincts a, b, c et d tels que a3 + b3 = c3 + d3. En utilisant un programme qui teste intelligemment tous les quadruplets possibles en utilisant des boucles for, pourriez-vous déterminer quel est le quadruplet pour lequel la somme a3 + b3 = c3 + d3 est minimale ?

Questions complémentaires

Questions complémentaires

Supposez que les variables a, b et x contiennent un nombre naturel. Ecrivez un fragment de code qui assignerait la valeur booléenne True à une variable nommée interval si x appartient à [a, b]. Assignez la valeur False sinon.









Supposez que les variables a, b et c contiennent un nombre naturel.

Ecrire un fragment de code qui assigne à la variable min le plus petit de ces nombres.









Ecrivez un programme qui permet de jouer au jeu fizzbuzz. Vous recevez un nombre (stocké dans la variable i). Nous allons implémenter une version simplifiée du jeu. Pour un entier i donné, le jeu va :

  • enregistre la string "fizz" dans la variable temp si le nombre est divisible par 3.
  • enregistre la string "buzz" dans la variable temp si le nombre est divisible par 5.
  • enregistre la string "fizzbuzz" dans la variable temp si le nombre est divisible par 3 et par 5.
  • enregistre la string "no" dans la variable temp si le nombre n'est divisible ni par 3, ni par 5.









Supposez que les variables a et b contiennent un nombre naturel.

Ecrivez un fragment de code qui assigne le reste de leur division à la variable rest.

Pour implémenter votre solution, utilisez uniquement une boucle while et des soustractions (la solution la plus simple rest = a % b n'est pas acceptée; nous voulons tester si vous êtes capable d'implémenter une telle opération par vous-même).

Notez que vous ne devez pas permettre la division par 0 et vous devez assigner la la valeur None à rest dans un tel cas.









<string>

Table des matières

Mission 3 - Fonctions et sous-problèmes

Mission 3 : Fonctions et sous-problèmes

Mission 3 : Fonctions et sous-problèmes

Introduction

UC Louvain

Le service Presse et Communication de l'Université fait appel aux étudiants de l'EPL pour étoffer ses ressources graphiques. Vous êtes chargés de produire des images de drapeaux et logos qui seront utilisés dans les médias de l'université. Pour produire ces dessins de nature géométrique, vous allez utiliser la programmation en Python en utilisant les graphiques tortue.

Objectifs

A l'issue de cette mission, chacun d'entre vous :

  • pourra expliquer et exploiter les notions suivantes en Python :
    • définition et appel de fonctions
    • paramètres et valeurs de retour
    • dessin avec la tortue
  • sera capable de décomposer un problème en sous-problèmes
  • pourra écrire une spécification précise d'un programme informatique

Préparation, étude et apprentissage

Vous devez lire et comprendre ces parties du syllabus pour pouvoir mener à bien cette mission :

Questionnaire de démarrage

Note

Pour vous aider dans la réalisation de ces exercices, certains d'entre eux sont disponibles sur Inginious avec une correction automatisée. Il a été fait en sorte que cette correction automatique soit utile à votre compréhension de la matière, cependant cela ne doit pas vous empêcher de discuter de vos réponses, correctes ou non, avec votre tuteur et les membres de votre groupe.

Questions à choix multiples

Les questions à choix multiples de cette mission sont également accessibles en ligne depuis https://inginious.info.ucl.ac.be/course/LSINF1101-PYTHON/Session3_QCM


        
        

Question 1

Définissez les concepts suivants et donnez un exemple :

  • définition d'une fonction
  • en-tête d'une fonction
  • documentation et spécification d'une fonction
  • corps d'une fonction
 
 
 
 
 
 

Question 2

Ecrivez l'en-tête et le corps d'une fonction baptisée afficheMax qui prend deux nombres entiers comme arguments et affiche le plus grand de ces nombres. La spécification de cette fonction est :

pre: -- post: affiche le maximum entre les nombres entiers a et b


        
        

Que faut-il changer pour faire une fonction calculeMax qui retourne le plus grand nombre au lieu de l'afficher ?

 
 
 
 

Question 3

Un étudiant montre à son tuteur le programme suivant :

hauteur = int(input("Hauteur de la croix: "))
print()
croix('X', hauteur)

Lors de son exécution, il affiche les caractères suivants à l'écran :

Hauteur de la croix: 9

    X
    X
    X
    X
XXXXXXXXX
    X
    X
    X
    X

Réécrivez l'en-tête, la spécification et le corps de la fonction croix utilisée par cet étudiant. (Pour rappel, print(x, end="") imprime x sans aller à la ligne ensuite.)

Question 4

Ecrivez l'en-tête, la spécification et le corps d'une fonction fact(n) qui calcule et retourne la factorielle de n : n! = n.(n − 1).(n − 2)…1. Veillez à ce que la méthode que vous écrivez respecte bien les spécifications que vous définissez vous-même.


        
        

Question 5

Le module math définit les constantes et fonctions mathématiques usuelles, telles que sqrt(x) (racine carrée), sin(x), cos(x), log(x) (logarithme), pi, etc. Ecrivez un programme qui imprime les valeurs de sin π/n pour n allant de 1 à 10.


        
        

Question 6

Quelle est la différence entre les trois instructions import suivantes ? Après ces instructions, comment réfère-t-on à la constante math.pi ?

import math
.

import math as m
.

from math import *
.

Question 7

Dans le programme suivant :

import turtle
t = turtle.Turtle()
t.color("blue")
print(t.heading())

Quelle est la nature (module, objet, fonction, méthode, …) des différents identifiants : turtle, Turtle, t, color, print, heading ?

 
 
 
 
 
 

Quelle est la signification de turtle.Turtle ? t.color ?

 
 

Question 8

Ecrivez un programme qui crée une tortue et trace en bleu un escalier de 3 marches de 20 unités descendant vers la droite.

 
 
 
 
 
 
 
 

Question 9

Dans cette mission, vous allez devoir utiliser la tortue pour dessiner le drapeau européen :

Le drapeau européen

Pour écrire un programme qui réalise ce dessin, il n'est pas souhaitable de commencer directement à écrire le code Python correspondant. Il faut d'abord décomposer ce problème complexe en sous-problèmes plus simples. On pourra ensuite écrire des fonctions pour résoudre chacun de ces sous-problèmes, et utiliser ces fonctions dans la fonction principale.

Expliquez en français quels sous-problèmes vous pouvez identifier dans ce problème. Discutez-en avec votre tuteur durant la séance intermédiaire afin d'identifier les fonctions que vous allez réaliser. Pour répondre à cette question, vous devez avoir une idée de la spécification et des paramètres de vos fonctions, il n'est pas nécessaire d'avoir déjà leur réalisation.

 
 
 
 
 
 
 
 
 
 

Mission 3

Mission 3

L'objectif final de cette mission est de produire à l'écran un dessin du drapeau de l'Union Européenne :

Le drapeau européen

Le drapeau européen

Pour y parvenir, vous allez devoir décomposer votre problème en une combinaison de sous-problèmes plus simples, et correctement et précisément spécifier ces sous-problèmes, les résoudre sous forme de fonctions Python, que vous utiliserez ensuite pour résoudre votre problème principal.

Vous allez travailler avec les graphiques tortue de Python, en utilisant le module turtle. Vous allez procéder par étapes.

  1. Organisation : vous travaillerez à nouveau en binômes de deux étudiants. Associez-vous à un étudiant différent de la semaine dernière; faites une tournante au sein de votre groupe.

  2. Considérez le programme suivant :

    import turtle                # module des graphiques tortue
    tortue = turtle.Turtle()     # créer une nouvelle tortue
    tortue.speed("fastest")      # tracé rapide
    
    def square(size, color):
        """Trace un carré plein de taille `size` et de couleur `color`.
    
        pre: `color` spécifie une couleur.
             La tortue `tortue` est initialisée.
             La tortue est placée à un sommet et orientée en direction d'un
             côté du carré.
        post: Le carré a été tracé sur la droite du premier côté.
              La tortue est à la même position et orientation qu'au départ.
        """
        tortue.color(color)
        tortue.pendown()
        tortue.begin_fill()
        for i in range(4):
            tortue.forward(size)
            tortue.right(90)
        tortue.end_fill()
        tortue.penup()
    

    Ce programme définit une fonction square qui trace un carré avec la tortue. Essayez de lire et de comprendre ce programme. Sur base de la spécification en tête de la définition de square, pouvez-vous prédire précisément le résultat de l'exécution de square(200, "red") ?

  3. Créez un nouveau fichier flags.py qui contiendra votre programme pour cette mission, et recopiez-y le programme ci-dessus. Exécutez-le dans Thonny, puis exécutez l'instruction square(200, "red") et observez son comportement. Le résultat est-il conforme à votre prédiction ? Testez les différentes couleurs disponibles :

    ["black", "blue", "green", "red", "magenta", "cyan", "yellow", "white"]
    

    Exécutez help(square) dans l'interpréteur pour afficher la documentation de square [1].

  4. Dans votre fichier, écrivez une fonction rectangle(width, height, color) qui trace un rectangle de dimensions width x height et de couleur color. Ecrivez d'abord la spécification, développez ensuite le code qui réalise cette spécification. Exécutez et testez votre programme.

  5. Ecrivez (et spécifiez) une fonction belgian_flag(width) qui dessine un drapeau belge de largeur width et de proportions 3/2. Utilisez bien sûr la fonction rectangle que vous venez de construire.

  6. Ecrivez (et spécifiez) une fonction plus générale three_color_flag(width, color1, color2, color3) qui dessine un drapeau tricolore de couleurs données. belgian_flag peut maintenant être re-défini comme three_color_flag(100, "black", "yellow", "red"). Ecrivez de même des fonctions dutch_flag, german_flag, luxemburg_flag et french_flag qui dessinent les drapeaux des pays voisins de la Belgique. Sur quelle fonction plus générale allez-vous vous baser ?

    Drapeaux de la Belgique et ses voisins
  7. Considérez maintenant le problème de dessiner le drapeau européen, comme représenté ci-dessus. Réfléchissez à comment décomposer ce problème en sous-problèmes, et spécifiez les différents sous-problèmes. Ecrivez ensuite les différentes fonctions réalisant ce problème, avec une fonction european_flag(width) qui dessine le drapeau.

  8. Pour parachever votre travail, écrivez un programme (en fin de votre fichier flags.py) qui affiche tous vos drapeaux dans une disposition de votre choix, par exemple :

    Tous les drapeaux
[1]Selon la version de Thonny que vous utilisez, il se peut que les caractères accentués ne s'affichent pas correctement dans la fonction help.

Remise de votre solution

Pour cette mission, vous devez soumettre votre programme flags.py et votre fichier README.txt au serveur de soumissions de programmes du cours. Votre fichier flags.py doit au moins contenir les fonctions :

square(size, color)
rectangle(width, height, color)
belgian_flag(width)
three_color_flag(width, color1, color2, color3)
european_flag(width)

        
        

Challenge

Pour aller plus loin, vous pouvez créer des fonctions pour dessiner d'autres drapeaux plus complexes, par exemple :

D'autres drapeaux

Grèce, Etats-Unis, Australie, Géorgie

Questions complémentaires

Questions complémentaires

The Greatest Divisor of a number a is the biggest number ( except a itself) such that the division of a by this natural is an entire division.

Since \(0\) is divisible by any natural this may cause some problems if you will look for the bigger one, so we expect you to return None.

Recall that the operator % returns the remainder of the Euclidian division.


        
        

Suppose you now have base € on your savings account.

If you leave it x years on that account at a fixed cummulative interest rate of y %, what will be the balance on your account after these x years?

Return that amount.


        
        

The Greatest Common Divisor of two natural numbers a and b is the biggest natural number k such that the division of a and b by this natural k is an entire division.

Euclid found a very simple recursive algorithm to find the GCD of two numbers: $$\text{gcd}(a,0) = a$$ $$\text{gcd}(a,b) = \text{gcd}(b,a\%b)$$

Recall that the operator % returns the remainder of the euclidian division.


        
        

In mathematics, the Fibonacci series are the numbers in the following sequence of integers, which is characterized by the fact that every number after the first two is the sum of the two preceding ones:

/Example: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...

A very simple algorithm would be: $$\text{F}_0 = 0$$ $$\text{F}_1 = 1$$ $$\text{F}_n = \text{F}_{n-1} + \text{F}_{n-2}$$

Create a function fibonacci(n) that prints the nth element of the Fibonacci sequence.


        
        

The Body mass index (BMI) or Quetelet index, used by dieticians, is indicative of the condition of a person.

A normal person should have an index between 20 and 25. Below 20, she is considered thin, above 25 overweight. Beyond 30, the person is obese!

This index is calculated as the ratio between a person's weight, expressed in kg, and the square of the person's height, expressed in meters.

Create a function quetelet(height, weight) to calculate a person's Quetelet index and return thin string for a person with an index strictly less than 20, normal for a person whose index is between 20 and 25, overweight if the index is strictly greater than 25 and less than or equal to 30 and obese when it is strictly greater than 30.


        
        

The police is hiring you to develop a program to calculate the fine that a car driver will have to pay in the event of a violation. The law stipulates that the driver will have to pay 5 euros per km/h above the maximum authorized speed, with a minimum fine of 12.5€.

For any speeding of more than 10 km/h above the authorized speed, the fine is DOUBLED!

Your program takes as input the maximum allowed speed and the actual speed of the car. It calculates the possible fine.

Example:

  • If the maximum speed is 50km/h and the vehicle is traveling at 62km/h, the penalty will be 12 * 5 * 2 = 120€.
  • If the maximum speed is 50km/h and the vehicle is traveling at 56km/h, the penalty will be 6 * 5 = 30€.
  • If the maximum speed is 50km/h and the vehicle is traveling at 51km/h, the fine will be 12.5€.


        
        

Les équations du second degré sont des équations de la forme suivante:

ax2 + bx + c = 0

avec a ≠ 0

Pour déterminer si l'équation dispose d'une solution, on calcule le nombre ρ = b2 − 4ac. Si ρ est strictement positif, l'équation a exactement deux solutions. La première solution s'obtient via la formule suivante :

( − b + (ρ))/(2a)

Et la seconde racine s'obtient via la formule suivante :

( − b − (ρ))/(2a)

Si ρ est nul, l'équation a exactement une solution, dont la valeur est égale à  − b ⁄ (2a). Si ρ est négatif, l'équation n'a aucune solution.

Pour montrer que vous maîtrisez la décomposition en sous-problèmes, vous devrez définir trois fonctions. Chacune d'entre elles prendra uniquement comme paramètres les valeurs de a, b et c. Tout d'abord, définissez et implémentez la fonction rho, qui retourne la valeur du nombre ρ.

Ensuite, définissez et implémentez la fonction n_solutions, qui retourne le nombre de solutions de l'équation définie par a, b et c.

Finalement, définissez et implémentez la fonction solution, qui retourne la solution d'une équation qui n'a qu'une seule solution et la plus petite solution d'une équation qui a deux solutions. La fonction ne sera jamais appelée pour une équation qui ne dispose pas de solution.

Les fonctions n_solutions et solution doivent impérativement faire appel à la fonction rho .

Pour résoudre l'exercice, vous aurez besoin de la fonction racine_carree, décrite ci-dessous. Cette fonction est déjà implémentée, vous ne devez donc pas l'écrire vous-même.

def racine_carree(n):
"""
Calcule une racine carree
pre: n est un nombre réel
     n >= 0
post: retourne la racine carrée réelle de n
"""

Voici un exemple d'utilisation des fonctions que vous devez implémenter, avec l'équation x2 + 2x + 1 = 0 :

rho(1, 2, 1)
>>> 0

n_solutions(1, 2, 1)
>>> 1

solution(1, 2, 1)
>>> -1.0


        
        
<string>

<string>

Table des matières

Mission 4 - Strings et listes

Mission 4 : Strings et listes

Mission 4 : Strings et listes

Introduction

Une étudiante en biologie que vous venez de rencontrer vous demande de l'aide pour un problème de bioinformatique. Grâce aux progrès des techniques de séquençage automatiques de l'ADN, il est maintenant facile d'obtenir l'ADN d'un être vivant. L'ADN est composé de quatre types de bases : Adénine, Cytosine, Guanine et Thymine. Pour manipuler ces séquences ADN, les biologistes ont pris l'habitude de les représenter sous la forme d'une (longue) suite de caractères représentants les 4 bases qui forment l'ADN. A titre d'exemple, voici un extrait de séquence ADN provenant de la base de données GenBank:

LOCUS       SCU49845     5028 bp    DNA             PLN       21-JUN-1999
DEFINITION  Saccharomyces cerevisiae TCP1-beta gene, partial cds, and Axl2p
            (AXL2) and Rev7p (REV7) genes, complete cds.
...

ORIGIN
        1 gatcctccat atacaacggt atctccacct caggtttaga tctcaacaac ggaaccattg
       61 ccgacatgag acagttaggt atcgtcgaga gttacaagct Aaaacgagca gtagtcagct
      121 ctgcatctga agccgctgaa gttctactaa gggtggataa catcatccgt gcaagaccaa
      181 gaaccgccaa tagacaacat atgtaacata tttaggatat acctcgaaaa taataaaccg
      241 ccacactgtc attattataa ttagaaacag aacgcaaaaa ttatccacta tataattcaa
      301 agacgcgaaa aaaaaagaac aacgcgtcat agaacttttg gcaattcgcg tcacaaataa
...
     4861 ttctccactt cactgtcgag ttgctcgttt ttagcggaca aagatttaat ctcgttttct
     4921 ttttcagtgt tagattgctc taattctttg agctgttctc tcagctcctc atatttttct
     4981 tgccatgact cagattctaa ttttaagcta ttcaatttct ctttgatc

Une séquence d'ADN d'un gène peut être très longue. A titre d'exemple, on estime que l'ADN humain contient de l'ordre de 3×109 bases découpées en environ 20.000 gènes. L'ADN d'une bactérie contient de l'ordre de 4 millions de bases. Les biologistes ont séquencé l'ADN d'un grand nombre d'espèces qu'ils stockent dans des bases de données spécialisées comme GenBank. Le traitement de toutes ces données a mené à la création de la bio-informatique, discipline qui rassemble des biologistes et des informaticiens.

Afin d'aider cette étudiante en biologie, vous allez écrire durant cette mission vos premiers algorithmes de bio-informatique.

Objectifs

Objectifs individuels

A l'issue de ce problème, chacun d'entre vous :

  • sera en mesure d'être de plus en plus précis sur certains concepts sous-jacents à un programme Python simple (après une quatrième prise de connaissance) :
    • chaînes de caractères
    • listes
    • fonctions qu'on peut appliquer sur chaînes et listes
    • création de listes imbriquées
  • aura montré une capacité à écrire des méthodes permettant de manipuler des chaînes de caractères et des listes.

Préparation, étude et apprentissage

La matière relative à cette mission est décrite dans les sections suivantes du syllabus :

Il est cependant important que vous puissiez facilement vous y retrouver dans la documentation de Python pour y trouver les renseignements dont vous avez besoin pour écrire des programmes efficaces. Pour des fonctions qui peuvent être exécutées sur des chaînes de caractères, regardez ici.

Questionnaire de démarrage

Questions à choix multiple

Les questions à choix multiples de cette mission sont également accessibles en ligne depuis https://inginious.info.ucl.ac.be/course/LSINF1101-PYTHON/Session4_QCM


        
        

Question 1

Vous voulez dire bonjour à l'utilisateur de votre programme. Le nom de l'utilisateur est enregistré dans une variable appelée name et vous voulez enregistrer vos salutations dans une variable nommée hello. Cette chaine de caractères aura la forme suivante : "Hello, name!"

Par exemple, si "Charles" est assigné à name, votre code écrirait "Hello, Charles!" dans la variable hello.


        
        

Question 2

Etant donnée une chaîne de caractères stockée dans une variable l, par exemple, l = "louvain-la-neuve" ou l = "braine-le-compte", comment feriez-vous pour :

  • Afficher la longueur de la chaîne de caractères l
 
 

  • Afficher la chaîne l en majuscules
 
 

  • Afficher le premier caractère de l
 
 

  • Afficher le premier caractère de l en majuscule
 
 

  • Afficher toute la chaîne sauf le premier caractère
 
 

  • Afficher la chaîne avec le premier caractère en majuscule (sur les exemples, "Louvain-la-neuve" et "Braine-le-compte")
 
 

Question 3

La fonction maximum_index(lst) doit retourner l'index de l'élément avec la plus grande valeur dans une liste non vide. Par exemple: maximum_index([0,2,5,3]) doit retourner 2, puisque 5 est la plus grande valeur et apparaît en position 2. Définissez cette fonction.


        
        

Question 4

Nous voulons écrire une fonction positions(s,p) qui pour une chaîne de caractères s et un caractère p retourne la liste des positions où le caractère p apparaît dans s. Par exemple, pour positions("gtagaac","a") le résultat doit être [2,4,5].

  • Décrivez en mots la structure d'un programme Python qui peut résoudre ce problème.
 
 
 
 
 

  • Écrivez du code Python pour ce problème.
 
 
 
 
 

  • Écrivez une spécification de la fonction suivante:
def q(c1,c2):
  return c1.upper () == c2.upper ()
 
 
 
  • On veut modifier la fonction positions(c,p) de telle façon que la fonction ignore si un caractère est en majuscule ou en minuscule. Par exemple, dans ce cas positions("gtagaAc","A") donne aussi [2,4,5] comme résultat, puisque le cas n'est pas important. Modifiez la fonction positions(c,p), en utilisant la fonction q de la question précédente.
 
 
 
 
 

Question 5

Écrivez une fonction ajoute ( l, v ) qui pour une liste donnée l, ajoute le nombre v à la fin de la liste, si ce nombre n'est pas encore présent dans la liste. Si le nombre apparaît déjà, la liste doit rester non modifiée. Pour ce code:

l = [ 3, 1, 5, 4 ]
ajoute ( l, 4 )
ajoute ( l, 6 )
ajoute ( l, 7 )
ajoute ( l, 6 )
print ( l )

Le programme doit imprimer [ 3, 1, 5, 4, 6, 7 ]. La fonction ajoute ne retourne rien.


        
        

Question 6

  • Étudiez la fonction ci-dessous et écrivez une spécification pour la fonction, en utilisant des conditions pré and post!
def mysterieux(n):
  l = []
  for i in range(n):
    l2 = []
    for j in range(n):
      l2.append ( n )
    l.append ( l2 )
  return l
 
 
 
 
 

  • Écrivez une fonction carre(n).

Pour un nombre entier donné n, la fonction doit retourner la matrice

[ [         0,             1, ...,     n - 1 ],
  [         n,         n + 1, ..., 2 * n - 1 ],
  [     2 * n,     2 * n + 1, ..., 3 * n - 1 ],
  ...,
  [ (n-1) * n, (n-1) * n + 1, ..., n * n - 1 ] ]

Par exemple, pour n=4, la fonction retourne

[ [  0,  1,  2,  3 ],
  [  4,  5,  6,  7 ],
  [  8,  9, 10, 11 ],
  [ 12, 13, 14, 15 ] ]


        
        

Mission 4

Mission 4

Les séquences d'ADN sont composées d'un suite de caractères A, T, C et G. Pour traiter de telles séquences en Python, le plus simple est de les manipuler comme des chaînes de caractères.

Votre objectif durant cette mission est de développer quelques fonctions permettant de traiter des séquences d'ADN stockées sous la forme de chaînes de caractères.

Toutes les fonctions doivent être écrites dans un fichier avec le nom bioinfo.py. Vérifiez pour chaque fonction que la fonction est correcte en utilisant des exemples!

  1. La première fonction à écrire est la fonction is_adn(s). Elle prend comme argument une chaîne de caractères s et retourne True si la chaîne de caractères contient uniquement les caractères a, t, c ou g (à la fois en majuscules et en minuscules) et False sinon. Une chaîne de caractères vide ("") n'est pas considérée comme étant de l'ADN.

    De bons exemples à utiliser pour les tests sont ici: "acgac", "AcaA", aAaza, "".

  2. La deuxième fonction à écrire est la fonction positions(s, p). Elle prend comme arguments deux chaînes de caractères s et p. Elle retourne les positions des occurences de p dans s. Par exemple, pour ACGACCG (majuscules) et cg (minuscule) le résultat doit être [1,5]. Vous ne pouvez pas utiliser la fonction find de Python.

  3. La troisième fonction à écrire est baptisée distance_h. Elle calcule la distance de Hamming (http://fr.wikipedia.org/wiki/Distance_de_Hamming) entre deux chaînes de caractères de longueurs égales. En théorie de l'information, cette distance est définie comme étant le nombre de positions où les deux chaînes de caractères diffèrent. Voici quelques exemples qui devraient vous aider à mieux comprendre cette distance :

    Chaîne 1 Chaîne 2 Distance
    A A 0
    AG GG 1
    AG AT 1
    ATGAC ATGAC 0
    ATGAC AGGAG 2
    ATGAC TGACG 5

    Si les chaînes n'ont pas la même longueur, la fonction doit retourner None.

  4. La quatrième fonction à écrire est distances_matrice(l). Étant donné une liste de chaînes de caractères, la fonction doit calculer une matrice des distances de Hamming entre toutes ces chaînes de caractères. Par exemple, pour cette liste: ["AG", "AT", "GT", "ACG", "ACT" ] la fonction doit retourner:

    [ [     0,   1,    2, None, None ],
      [     1,   0,    1, None, None ],
      [     2,   1,    0, None, None ],
      [ None, None, None, 0,    1    ],
      [ None, None, None, 1,    0    ] ]
    

    Utilisez la fonction que vous avez écrit dans l'exercice précédente.

Remise de votre solution

Pour cette mission, vous devez soumettre votre fichier bioinfo.py au serveur de soumissions de programmes du cours. Votre fichier bioinfo.py doit au moins contenir les fonctions :

is_adn(text)
positions(text,car)
distance_h(text1,text2)
distances_matrice(l)

        
        
Questions complémentaires

Questions complémentaires

Écrivez une fonction recherche ( m, v ) qui pour un nombre entier donné v, retourne True si ce nombre apparaît dans la matrice, et False si non. Par exemple, pour la matrice suivante et la valeur v=4, le résultat doit être False. Pour la valeur v=3 le résultat doit être True.

[ [  0,  3,  2,  8 ],
  [  6,  5,  2,  1 ],
  [  7,  0,  3,  2 ] ]


        
        

La méthode sum(list) retourne la somme des éléments contenus dans list.

Exemple: la somme de [1,2,3] est 6

Notez que votre algorithme devrait être capable de calculer la somme même si la liste list contient des éléments malicieux (pas des nombres).


        
        

La méthode average(list) retourne la moyenne arithmétique des éléments contenu dans list, sauf si list est vide auquel cas, elle devrait retourner None.


        
        

La méthode diff_count(lst) retourne le nombre d'éléments différents contenus dans la liste lst.

Par exemple:

  • Si lst est égal à [3, 5, 3] alors la méthode devrait retourner 2.
  • Si tous les éléments sont les mêmes, la méthode devrait retourner 1.
  • Si la liste lst est vide, elle devrait retourner 0.


        
        

Les équations du second degré sont des équations de la forme suivante:

$$ax^2 + bx + c = 0$$

avec a ≠ 0

Pour déterminer si l'équation dispose d'une solution, on calcule le nombre ρ = b2 − 4ac. Si ρ est strictement positif, l'équation a exactement deux solutions. La première solution s'obtient via la formule suivante :

( − b + (ρ))/(2a)

Et la seconde racine s'obtient via la formule suivante :

( − b − (ρ))/(2a)

Si ρ est nul, l'équation a exactement une solution, dont la valeur est égale à  − b ⁄ (2a). Si ρ est négatif, l'équation n'a aucune solution.

Un étudiant vous demande de l'aider à résoudre des équations à tour de bras. Vous disposez de la fonction suivante, qui est une variante de la fonction implémentée dans un exercice complémentaire de la Session 3:

def solution(a, b, c):
"""
pre:  a, b et c sont 3 nombres réels
post: la valeur de retour de cette fonction dépend du nombre
      de solutions de l'équation ax^2 + bx + c = 0.
- 0 solution: retourne la liste vide
- 1 solution: retourne une liste contenant la solution de l'équation
- 2 solutions: retourne une liste contenant les deux solutions,
              la plus petite solution en première place
"""

Écrivez la signature et le corps de la fonction solveur, dont le but est de résoudre une liste d'équations du second degré. Une équation est représentée par la liste [a, b, c]. La fonction solveur doit retourner une liste. L'élément à l'indice i de la valeur de retour contient le résultat de la fonction solution appliquée sur l'équation située à l'indice i de l'input.

Pour réussir cette exercice, vous devez utiliser une list comprehension.

Voici un exemple de la valeur de retour de la fonction solveur :

>>> solveur([])
[]

>>> solveur([[1, 1, -1], [4, 4, 1], [1, 2, 3], [-1, 2, 3]])
[[-1.618033988749895, 0.6180339887498949], [-0.5], [], [-1.0, 3.0]]


        
        

Une fois de plus, la Grosse Dame a bu tout le vin de la peinture des moines ivres et le Chevalier du Catogan n'est pas disponible pour la remplacer. L'accès à la salle commune des Gryffondor n'est pas gardée et les intentions des Serpentards sont mauvaises.

Nous avons besoin que vous conceviez un vérificateur de mot de passe pour combler le vide laisser par le départ de la Grosse Dame.

Créez une fonction portrait(right_password, entered_password) qui retourne True si les deux mots de passe sont identiques et False sinon.


        
        

Anonymous vient de vous engager sur le dark web pour une tâche dangereuse. Ils essayent de craquer un code depuis quelques jours mais ne sont arrivés à rien... pour le moment!

Ils veulent que vous construisiez une fonction qui analysera chaque caractère dans un code donné et que vous déterminiez sa nature. Le but est simple : ils ont l'intention d'utiliser les informations que vous leur fournirez pour trouver un pattern dans le code.

Créez une fonction extract(code) pour fournir des infos concernant la nature de chaque élément du code :

Par exemple, si le code 'AeB7' est donné en entrée, la fonction devrait produire 'vowel-up vowel-low consonant-up number' comme sortie. En général :

  • Ajoutez un number à la réponse si l'élément du code est un chiffre.
  • Ajoutez un vowel à la réponse si l'élément du code est une voyelle.
  • Ajoutez un consonant à la réponse si l'élément du code est une consonne.
  • Suivez cela par -up si la voyelle/consonne est en majuscule.
  • Suivez cela par -low si la voyelle/consonne est en minuscule.

Exemple :

Avec le code '65AeBc7' la fonction devrait sortir 'number number vowel-upvowel-low consonant-up consonant-up number'.


        
        

Etant donné que votre travail était remarquable, Anonymous vous a à nouveau contacté avec une autre tâches risquée. Ils manquent de main d'oeuvre et aimeraient que traitiez les données que vous leur avez donné.

Ils veulent que vous construisiez une fonction qui transformera votre précédente sortie en quelque chose de plus simple et plus rapide à traiter. C'est à vous de voir comment transformer l'information en un pattern utilisable!

Créez une fonction treatment(data) pour transformer l'information que vous avez précédemment retourné en un pattern :

Chaque suite d'éléments communs devrait être indiqué par la nature de l'élément suivi de '*' et le nombre d’occurrence sans autre éléments entre.

Exemple:

Avec le code '66AeB7' votre précédente fonction sortirait 'number number vowel-up vowel-low consonant-up number'.

Avec cette sortie en entrée votre nouvelle fonction treatment sortirait la string suivante 'number*2 vowel-up*1 vowel-low*1 consonant-up*1 number*1'.

N'hésitez pas à utiliser autant de sous-méthodes que vous jugez nécessaires.


        
        

Nombres premiers

Les nombres premiers (https://en.wikipedia.org/wiki/Prime_number) sont des nombres avec les caractéristiques suivantes:

  • ce sont des nombres plus grands que 1
  • ils n'ont pas des diviseurs autres que 1 et eux-mêmes.

Des nombres premiers sont 2, 3, 5, 7, 11, 13, ...

Pour calculer les nombres premiers on peut utiliser le crible d'Eratosthène : pour chaque nombre successif, on vérifie si on peut le diviser par un des nombres premiers déjà trouvés. Si non, on peut ajouter le nombre à la liste. Ecrivez la fonction primes(max) qui retourne une liste de tous les nombres premiers jusque max (max inclus si max est un nombre premier). Si max est négatif ou zéro, la liste vide doit être retournée.

Pour limiter la complexité de la solution, decomposez votre solution en sous-problèmes comme nécessaire; utilisez des boucles for.


        
        

<string>

Table des matières

Mission 5 - Tuples, Tests et Algorithmes de Recherche

Mission 5 : Tuples, Tests, et Algorithmes

Mission 5 : Tuples, Tests, et Algorithmes

Introduction

Vous travaillez pour une entreprise qui est active dans toute la Belgique. En tant que composant d'un système plus grand, l'entreprise a besoin d'outils qui permettent de rechercher les coordonnées des communes belges. Vous avez trouvé une liste des communes et leur coordonnées GPS en ligne et devez utiliser Python pour créer les outils demandés.

Objectifs

Objectifs individuels

A l’issue de ce problème, chacun d’entre vous :

  • sera en mesure d’exploiter les notions suivantes :
    • tuples
    • algorithmes de recherche linéaire et binaire
    • tests
  • aura modifié un algorithme de recherche binaire pour l'utilisation dans une situation spécifique
  • aura découpé un gros problème en petits problèmes

Objectifs collectifs

A l’issue de ce problème, le groupe tout entier :

  • aura montré sa capacité à travailler ensemble pour répondre à une série de questions relatives à ce qui aura été appris dans le cadre de la mission,
  • peut lire et écrire des spécifications qui sont lisibles pour les autres membres de l'équipe,
  • peut écrire des testes pour vérifier la fonctionnalité de fonctions écrites par d'autres membres de l'équipe.

Préparation, étude et apprentissage

La matière relative à cette mission est décrite dans les sections suivantes du syllabus en ligne :

Questionnaire de démarrage

Questions à choix multiple

Les questions à choix multiples de cette mission sont également accessibles en ligne depuis https://inginious.info.ucl.ac.be/course/LSINF1101-PYTHON/Session5_QCM


        
        

Question 1

Dans cet exercice, nous étudions les listes de nombres entiers ordonnées de façon strictement croissante. Un exemple d'une telle liste est [-1,0,3,5]; la liste [-1,0,0,2] ne l'est pas (puisque 0 et 0 sont égales).

  • Étant donnée une liste de nombres entiers, comme [-2,0,3,4] ou [3,-2,0], écrivez une fonction def is_sorted(l) avec la spécification suivante:

    def is_sorted ( l ):
        """ Retourne si la liste l est ordonnée de façon strictement croissante.
    
        Args:
            l: une liste de nombres entiers, positif ou négatif
        Retourne:
            Un booléen qui indique si la liste l est ordonnée de façon strictement croissante.
        """
    

 
 
 
 
 
  • Écrivez 6 tests en utilisant assert pour évaluer si la fonction is_sorted(l) a été mise en oeuvre correctement.
 
 
 
 
 
 

  • Étant données deux listes ordonnées de façon strictement croissante, on veut calculer une nouvelle liste ordonnée des nombres entiers qui sont communs entre les deux listes. Par exemple, étant données les listes [-2,-1,0,1,2,3,4] et [0,1,2,5,6], on veut calculer la liste [0,1,2], qui contient les nombres entiers [0,1,2] qui sont communs entre les deux listes. Une première implémentation de cette idée est donnée ci-dessous.

    def intersect ( l1, l2 ):
        """ Retourne une liste ordonnée des nombres entiers communs entre l1 et l2.
    
        Args:
            l1: une liste ordonnée de nombres entiers, positif ou négatif
            l2: une liste ordonnée de nombres entiers, positif ou négatif
        Retourne:
            Une liste ordonnée de nombres entiers communs entre l1 et l2.
        """
        l = []
        for e1 in range(len(l1)):
            for e2 in range(len(l2)):
                if e2 == e1:
                    l.append ( e1 )
        return l
    

    Malheureusement, le code ne fonctionne pas encore correctement. Écrivez un test qui montre que le code n'est pas correct.

 
 

  • Écrivez un test sur lequel le code (incorrect) marche correctement; dans ce test la fonction doit être appelée avec deux listes de longueur 3.
 
 

  • Corrigez l'erreur en modifiant deux lignes de code de la fonction.
 
 
 
 
 
 

Question 2

Donnée est une liste de coordonnées, comme par exemple:

coordonnees = [(0,1),(2,3),(0,1),(4,5),(1,2),(0,1),(1,1),(0,2),(1,1)]

  • Étant donnée une coordonnée (i,j), créez une fonction count(cordonnees,i,j) pour calculer le nombre de fois que la coordonnée (i,j) apparaît dans la liste.

        
        

  • Étudiez le code suivant:

    coordonnees = [(0,1),(2,3),(0,1),(4,5)]
    
    def f ( v ):
        return v*v
    
    def increment ( l ):
        for i in range(len(l)):
            l[i][0] = f(l[i][0])
    
    increment ( coordonnees )
    assert coordonnees == [(0,1),(4,3),(0,1),(16,5)]
    

    Malheureusement le code donne une erreur et ne passe pas le test. Corrigez une ligne de la fonction increment(l) de telle sorte que le code passe le test.

 
 
 
 
 
 

Question 3

On représente les cours suivis par des étudiants en utilisant des listes imbriquées, comme suit:

[('LINFO1101', ['Jean', 'Pierre']), ('LINFO1110', ['Jean']),\
  ('LINFO1111', ['Jean']), ('LINFO1112', ['Jacques', 'Pierre']),\
  ('LINFO1113', ['Pierre'])]

Donnez un algorithme binary_search(course,list_of_courses) pour trouver tous les étudiants d'un cours donné dans cette structure de données. Copiez le code du cours et modifiez-le.


        
        

Question 4

On peut appliquer l'algorithme de question 3 pour trouver les étudiants de plusieurs cours. Supposez que chaque fois que vous calculez middle, tu imprimes la valeur calculée pour middle. Dans ce cas, le nombre de valeurs imprimées pour middle correspond à la nombre de fois que la boucle while est exécutée. Combien de fois est-ce que la boucle est exécutée pour l'exemple suivant ?

La liste est:

[('LINFO1101', ['Jean', 'Pierre']), ('LINFO1110', ['Jean']),\
 ('LINFO1111', ['Jean']), ('LINFO1112', ['Jacques', 'Pierre']), \
 ('LINFO1113', ['Pierre'])]

Les cours donnés sont: LINFO1110, LINFO1112, LINFO1111, LINFO1114.

 
 
 

Mission 5

Mission 5

Pour cette mission, vous devez écrire des fonctions et tester leur bon fonctionnement. Comme dans les exercices de préparation, vous devez travailler à deux de cette façon: pendant qu'un étudiant écrit une fonction, l'autre développe la fonction de test correspondante. Lorsqu'une fonction est correctement spécifiée, on peut écrire les tests permettant de vérifier son bon fonctionnement sans connaître son code.

Dans cette mission vous allez créer plusieurs fonctions qui fonctionnent sur une liste de communes de la Belgique.

Etapes

Téléchargez le fichier sorted_belgian_communes.py, qui contient une liste de toutes les communes de la Belgique ainsi que leurs coordonnées (selon une projection Mercator). Ecrivez toutes les fonctions demandées durant cette mission dans ce fichier.

Etape 1

  • Écrivez une fonction verify_order(communes) qui vérifie que la liste de communes communes est triée par nom. Cette fonction doit retourner True quand la liste est triée, et False autrement. Écrivez une spécification de la fonction dans le style de Google!
  • Écrivez des tests pour cette fonction, en utilisant des exemples plus petits. Les tests doivent se baser sur la spécification de la fonction, comme convenu avec votre partenaire. Ajoutez les tests dans le même fichier, dans une fonction test_verify_order() sans arguments. Dans cette fonction de test, des instructions assert doivent être utilisé pour vérifier l'exactitude de la fonction verify_order(communes).

Finalement, appliquez votre fonction à la liste all_communes.

Etape 2

  • Écrivez une fonction coordinate(commune,all_communes) pour trouver les coordonnées d'une commune dans la liste all_communes, basé sur le nom de la commune. Utilisez une variation de binary_search. La fonction doit retourner un tuple qui représente les coordonnées selon la projection Mercator.
  • Écrivez des tests pour cette fonction, en utilisant des exemples plus petits. Ajoutez les testes dans le même fichier, dans une fonction test_coordinate().

Etape 3

Écrivez une fonction distance(commune1, commune2, all_communes) pour calculer la distance euclidienne entre deux communes dont les noms sont donnés. La distance euclidienne entre deux coordonnées (x1,y1) et (x2,y2) est:

((x1 − x2)2 + (y1 − y2)2)

Rappel: le module math contient une implémentation d'une fonction sqrt. Écrivez une fonction auxiliaire pour calculer la distance entre deux coordonnées (x1,y1) et (x2,y2).

De nouveau: ajoutez des spécifications pour toutes les fonctions, ainsi que des tests, dans une fonction test_distance().

Etape 4

Écrivez une fonction tour_distance(communes, all_communes) pour calculer la distance totale d'une tournée à travers toutes les communes dans la liste communes. La tournée commence à communes[0], va ensuite vers communes[1], communes[2], ..., communes[-1], pour finalement retourner à communes[0].

De nouveau: ajoutez des spécifications pour la fonction, ainsi que des tests, dans une fonction test_tour_distance().

Remise de votre solution

Pour cette mission, vous devez soumettre votre fichiers sorted_belgian_communes.py et README.txt au serveur de soumissions de programmes du cours. Les fonctions et les testes doivent être dans le même fichier. Le fichier ne doit contenir que des fonctions (en plus de la variable all_communes). Votre fichier sorted_belgian_communes.py doit au moins contenir les fonctions :

verify_order(communes)
coordinate(commune,all_communes)
distance(commune1, commune2, all_communes)
tour_distance(communes, all_communes)

        
        
Questions complémentaires

Questions complémentaires

Question 0

Les questions ci-dessous sont des questions supplémentaires de Question 1 de la phase de préperation; ce sont des questions à faire sur papier.

  • Déterminez combien de fois la ligne de code if e2 == e1: est executée pour le cas de test suivant:

    assert intersect ( list(range(100)), list(range(100)) ) == list(range(100))
    
 
 

  • On va essayer de résoudre le problème plus efficacement. Une idée est de parcourir les deux listes en même temps; pour chaque élément de la première liste, on regarde si on peut trouver l'élément dans la partie de la deuxième liste qu'on n'a pas encore parcouru. Cette idée a été mise en oeuvre dans la fonction suivante:

    def intersect ( l1, l2 ):
        """ Retourne une liste ordonnée des nombres entiers communs entre l1 et l2.
    
        Args:
            l1: une liste ordonnée de nombres entiers, positif ou négatif
            l2: une liste ordonnée de nombres entiers, positif ou négatif
        Retourne:
            Une liste ordonnée de nombres entiers communs entre l1 et l2.
        """
        l = []
        p1 = 0
        p2 = 0
        while p1 < len(l1):
            while l1[p1] > l2[p2]:
                p2 += 1
            if l1[p1] == l2[p2]:
                l.append ( p2 )
            p1 += 1
        return l
    

    Malheureusement, le code ne fonctionne pas encore correctement.

    Écrivez quelques testes qui permettent de découvrir que le code n'est pas correct.

 
 
 
 

  • Corrigez le programme pour résoudre le problème, sans ajouter des lignes au programme.
 
 
 
 
 
 

Question 1

Donnée est une liste de coordonnées. Par exemple:

System Message: ERROR/3 (<string>, line 105)

Content block expected for the "code-block" directive; none found.

.. code-block:: python

l = [ ( 2.0, 5.0 ), ( 8.0, 12.0 ), ( 10.0, 40.0 ), (8.0, 50.0), (8.0, 50.0) ]

Nous voulons créer un dictionnaire pour identifier rapidement les valeurs y pour une x donnée. Pour l'exemple:

System Message: ERROR/3 (<string>, line 112)

Content block expected for the "code-block" directive; none found.

.. code-block:: python

d = { 2.0: [ 5.0 ], 8.0: [ 12.0, 50.0, 50.0 ], 10.0: [ 40.0 ] }

Écrivez une fonction create_dict(l) qui crée cette dictionnaire (pas limité à cet exemple).


        
        

Question 2

Donnée est une liste de coordonnées, comme dans l'exercice précédente. Nous voulons créer un dictionnaire pour identifier rapidement la valeur maximale Pour l'exemple:

System Message: ERROR/3 (<string>, line 150)

Content block expected for the "code-block" directive; none found.

.. code-block:: python

d = {2.0: 5.0, 8.0: 50.0, 10.0: 40.0}

Écrivez une fonction create_dict_max(l) qui crée ce dictionnaire (pas limité à cet exemple).


        
        

  • Écrivez une fonction get_ordered_list(l) selon les spécifications suivantes, ainsi que les tests pour vérifier l'exactitude de cette fonction. (La fonction est écrite par membre B de votre groupe; les tests sont écrit par membre A.)
def get_ordered_list ( l ):
    """ Retourne les chaînes de caractères dans la liste l dans l'ordre indiquée par la liste l

    L'ordre est déterminée par les nombres entiers dans la liste: pour chaque tuple e dans la liste l,
    le successeur est l[e[1]], si e[1] != None.

    Args:
        l:  une liste de tuples, dont chacun se compose d'une chaîne de caractères et un nombre entier ou None;
            les nombres entiers définissent un ordre total sur les éléments de la liste.
    Retourne:
        Les chaines de caractères dans la liste l dans l'ordre indiqué par les nombres entiers.
    """
 
 
 
 
 
 
 
 
 
 

Nous avons la structure de données suivante pour stocker la relation entre étudiants et cours qu'ils ont suivis:

student_courses = [ ( "Jean", "LINFO1111" ), ( "Jean", "LINFO1101"), \
     ( "Pierre", "LINFO1101" ), ( "Pierre", "LINFO1112" ) ]

Écrivez le code pour ajouter un tuple ("Jacques", "LINFO1112") à student_courses.


        
        

Créez une fonction students(course, student_courses) qui, pour un cours donné, renvoie une liste des étudiants qui suivent le cours. Par exemple, si on appelle la fonction avec "LINFO1101" et la liste de la question 3 comme paramètres, le résultat doit être ["Jean", "Pierre"].

On présume qu'il n'y a pas d'ordre dans la liste student_courses.


        
        

Écrivez une fonction remove_student(student,student_courses) qui, pour un étudiant donné présent dans une liste donnée, retourne la liste sans les tuples qui concernent cet étudiant.

System Message: ERROR/3 (<string>, line 265)

Unexpected indentation.

Par exemple, si on appelle la fonction avec "Jean" et la liste de la question 1 comme paramètres le résultat doit être :

[ ( "Pierre", "LINFO1101" ), ( "Pierre", "LINFO1112" ) ]

On présume qu'il n'y a pas d'ordre dans la liste student_courses.

Question 3

Écrivez une fonction nest_students(student_courses) qui, pour chaque cours, crée une liste imbriquée des étudiants qui suivent le cours. Sur l'exemple précédent, la fonction doit retourner cette structure de données:

[('LINFO1101', ['Jean', 'Pierre']), ('LINFO1111', ['Jean']), ('LINFO1112', ['Pierre'])]

La liste doit être triée par ordre de cours. Utilisez le code de question 4 et de question 5 comme inspiration. Réfléchissez sur la question: comment est-ce qu'on peut ajouter un élément dans une liste imbriquée qui vient d'être créée?


        
        

Vous faites partie de l'organisation des 5 et 10 miles de Louvain-la-Neuve. Mais le système est tombé en panne juste avant le départ.

Il y avait deux étudiants pour prendre note des arrivées des coureurs. Heureusement, il n'y avait que deux lignes à compter. Votre job consiste à faire une liste de ces deux listes pour avoir un classement général.

Les listes que vous recevez sont une succession de ['name', time] avec le temps dans un ordre croissant. Créez une fonction merge(first_list, second_list) qui retournera une liste qui a les éléments des deux listes dans l'ordre.


        
        

En sciences informatiques, un algorithme de tri est un algorithme qui place les éléments d'une liste dans un certain ordre. Les ordres les plus utilisés sont l'ordre numérique et l'ordre lexicographique. Un tri efficace est important pour optimiser l'utilisation d'autres algorithmes (tels que les algorithmes de recherche ou de fusion) qui ont besoin d'une liste triée en entrée ; c'est aussi souvent utile pour la canonicalisation des données et pour produire des sorties lisibles par les humains. Plus formellement, la sortie doit satisfaire deux conditions :

  • La sortie est en ordre croissant (chaque élément n'est pas plus petit que l'élément précédent selon l'ordre choisi);
  • La sortie est une permutation (réorganisation mais avec tous les éléments originaux) de l'entrée.


        
        

Une fois de plus, c'est l'heure de la cérémonie de la répartition . Les premières années attendent en rangs devant un vieux chapeau, à la fois anxieux et excités. Le directeur fait un long discours pour les accueillir et laisse la place à un mystérieux intervenant.

Tous les premières années sont ébahis lorsque le Choixpeau Magique brise le silence en chantant l'une de ses célèbres chansons.

Cependant, le choixpeau en fait un peu trop et rencontre quelques problèmes. Il perd sa voix et ne sera pas en état d'assurer la suite de la cérémonie. Heureusement, nous avons toujours accès aux connaissances des fondateurs et nous pourrons répartir les élèves avec votre aide.

Créez une fonction house_designation(student_qualities) qui va retourner une liste avec les noms des quatres maisons, la première étant celle où l'étudiant devrait aller et la dernière, celle qui convient le moins à l'étudiant. Pour décider de cette répartition, l'étudiant devrait être placé dans la maison où il a le plus d'affinités, c'est-à-dire, la maison avec laquelle il partage le plus de qualités. Si deux maisons sont à égalité, on les retourne dans l'ordre dans lequel elles sont placées dans les connaissances des fondateurs.


        
        










<string>

Table des matières

Mission 6 - Fichiers et exceptions

Mission 6 : Fichiers et exceptions

Mission 6 : Fichiers et exceptions

Introduction

Vous allez développer un programme qui permets l’exécution de certaines tâches. Très fréquemment, un utilisateur doit faire les tâches suivantes :

  • Operations arithmétiques (ex. addition des chiffres) ;
  • chercher des mots dans un dictionnaire ;
  • calculer des statistiques d'un fichier.

Les exercices préparatoires vous permettent de completer certains éléments de cette mission.

Objectifs

Objectifs individuels

A l’issue de ce problème, chacun d’entre vous sera en mesure d’exploiter les notions suivantes :

  • exceptions ;
  • fichiers ;
  • opérations plus compliquées sur chaînes de caractères.

Préparation, étude et apprentissage

La matière relative à cette mission est décrite dans les sections suivantes du syllabus en ligne :

Il peut être utile de relire:

Questionnaire de démarrage

Questions à choix multiple

Les questions à choix multiples de cette mission sont également accessibles en ligne depuis https://inginious.info.ucl.ac.be/course/LSINF1101-PYTHON/Session6_QCM


        
        

Question 1

Considérez le code suivant:

file = open ( "file.txt", "r" )
for line in file:
    print  ( line.strip ().split (",") )
file.close ()

Le contenu du fichier file.txt est le suivant:

X   , X   , \n   , X \n X X , , X

Expliquez le résultat de code.

 
 
 
 
 
 

Question 2

Dans les exercices suivants, vous pouvez supposer que les fichiers à lire existent et qu'il ne faut pas traiter les erreurs.

  • Créez une fonction line_count(filename) qui retourne, pour le nom d'un fichier donné, le nombre de lignes dans le fichier.
  • Créez une fonction char_count(filename) qui retourne, pour le nom d'un fichier donné, le nombre de caractères dans le fichier.
  • Créez une fonction space(filename,n) qui crée un nouveau fichier filename qui se compose seulement de n espaces.
  • Créez une fonction capitalize(filename_in,filename_out) qui crée, pour le fichier filename_in, un nouveau fichier filename_out, dont le contenu est le même, sauf que tous les caractères sont en majuscule.


        
        

Question 3

On donne des listes contenant des paires de coordonnées comme [(0.5,0.5),(0.1,0.3),(0.4,0.5)].

  • Écrivez une fonction read_coordinates(filename) qui lit les coordonnées du fichier filename, dans le format suivant, et retourne une liste de tuples, comme donnée.
0.5,0.5
0.1,0.3
0.4,0.5
  • Écrivez une fonction write_coordinates(filename, l) pour créer un fichier qui contient les coordonnées de la liste l dans le format ci-dessus.

Considérez l'utilisation de méthodes de string telles que : * split * strip

Voyez la documentation de ces méthodes dans le manuel de référence de Python.

Dans cet exercice, les erreurs possibles lors de la lecture ou de l'écriture d'un fichier peuvent être ignorées.


        
        

Question 4

Considérez le code suivant.

command = input ( "Enter your command: " )
parameters = command.split ()
if parameters[0] == "divide":
    print ( "The value of your division is: " + str ( float(parameters[1])/float(parameters[2])))
elif parameters[0] == "showfile":
    file = open ( parameters[1] )
    print ( file.read () )
    file.close ()
else:
    print ( "Command not recognized")
  • Identifiez quelles erreurs pourraient survenir lors de l'exécution de ce code. Il n'est pas nécessaire d'identifier les noms exacts des erreurs en Python; il suffit de décrire les erreurs en français.
 
 
 
 
 
 

  • Ajoutez un bloc try ... except pour attraper les exceptions d'une façon générique. Donnez un message générique There was an error dans ce cas. Assurez-vous que le fichier est aussi correctement fermé en cas d'erreur!
  • Modifiez le code tel que dans le cas d'une commande qui n'existe pas, une exception est lancée.


        
        

  • (Seulement à faire s'il reste du temps.) Modifiez le bloc try ... except pour que les messages soient plus informatifs. Pour cet exercice, vous devez exécuter le code et déclencher les différentes erreurs afin de déterminer leur nom (comme ValueError, FileNotFoundError, ...). Vous trouvez la liste de toutes les différentes exceptions sur https://docs.python.org/3/library/exceptions.html, mais il est plus facile de déterminer leur nom en regardant les messages de Python.
 
 
 
 
 
 

Question 5

Dans la mission, vous devrez lire un fichier qui contient des mots avec leur fréquence d'occurrence. Par exemple:

this,5146
that,10790
these,1575
the,69975
those,864

Identifiez les différentes erreurs que l'on pourrait rencontrer en lisant ce fichier. Il n'est pas nécessaire d'identifier les noms exacts des erreurs; il suffit de les décrire en mots.

 
 
 
 
 
 

Mission 6

Mission 6

Dans cette mission nous allons développer un simple assistant qui fonctionne sur la console Python. L'utilisateur doit être capable de donner des commandes simples, pour lesquelles l'outil doit répondre avec une réponse pertinente. L'objective dans cette mission est de montrer que l'outil continue à fonctionner même si l'utilisateur donne des commandes incomplètes ou incorrectes.

Les commandes qui doivent être supportées sont:

  • file <name>: spécifie le nom d'un fichier sur lequel l'outil doit travailler à partir de ce moment
  • info: montre le nombre de lignes et de caractères du fichier
  • words: utilise le fichier comme liste de mots à partir de maintenant
  • search <word>: détermine si le mot est dans la liste de mots
  • sum <number1> ... <numbern>: calcule la somme des nombres spécifiés
  • avg <number1> ... <numbern>: calcule la moyenne des nombres spécifiés
  • help: montre des instructions à l'utilisateur
  • exit: arrête l'outil

Par exemple, l'outil doit supporter cette séquence de commandes :

Welcome to your personalized tool!
> file all-words.dat
Loaded all-words.dat
> info
11304 lines
1330218 caracters
> words
Read file as list of words
> search presbytaerial
Presbytaerial is not in the list of words
> search presbyterial
Presbyterial is in the list of words
> exit

Si l'utilisateur spécifie un fichier autre qu'une liste de mots, ou si l'utilisateur cherche un mot sans avoir spécifié une liste de mots, l'outil doit produire un message d'erreur et continuer à fonctionner.

Le format des listes de mots est spécifié dans les exercices préparatoires. Pour éviter tout problème avec l'encodage des caractères accentués, votre liste de mots vérifiera des mots en anglais (sans accents).

Note: dans cet exercice, la liste de mots ne doit pas encore être mise en oeuvre à l'aide de dictionnaires Python, ce qui sera le sujet de la mission de la semaine prochaine.

La phase de réalisation de cette mission est moins guidée que les précédentes; vous devez choisir vous-même la subdivision de votre programme en fonctions.

Néanmoins, on vous suggère de procéder comme suit:

  • Commencez avec une boucle while qui demande à l'utilisateur de donner des commandes.
  • Utilisez le code de la phase de préparation pour lire des commandes et réagir sur les commandes.
  • Écrivez au moins une fonction séparée pour chaque commande.
  • Utilisez des variables globales pour stocker l'état de l'outil (par exemple le nom du fichier).
  • Au début vous pouvez ignorer les erreurs: assurez-vous que l'outil fonctionne si l'utilisateur donne des commandes correctes.
  • Ensuite, améliorez le code afin que le programme continue quand une commande incorrecte est donnée.

Pour vous aider, vous avez à disposition le fichier all-words.dat qui contient une centaine de milliers de mots de la langue anglaise ainsi que le nombre d'occurrences de ce mot. Cette liste de mots a été construit en se basant sur deux sources d'information : les mots utilisés par ispell (http://wordlist.sourceforge.net/) et la Global Service List (http://jbauman.com/gsl.html), c'est-à-dire les 2000 mots les plus fréquemment utilisés par un personne qui apprend l'anglais. Ce fichier contient les mots en minuscules et n'est pas trié dans l'ordre alphabétique. La première ligne contient le nombre de mots présents dans le fichier.

La mission de cette semaine n'aura pas de correction automatique donc soyez bien attentifs pendant la séance de feedback.

Tests

Vous devrez aussi écrire des tests de vos fonctions. Si assistant.py est le fichier qui contient votre code, nous attendons que vous écrivez un deuxième fichier test.py dans lequel vous faites des appels aux fonctions que vous avez fournies. Il est décrit dans le syllabus théorique comment faire des tests quand on a plusieurs fichiers (Section Tests).

Remise de votre solution

Vous devez soumettre un fichier assistant.py avec le code de votre outil et un fichier test.py avec vos tests. N'oubliez pas d'ajouter dans ce fichier des spécifications (docstrings) et aussi d'écrire un fichier README.


        
        
Questions complémentaires

Questions complémentaires

Écrivez un outil qui fait le suivant:

  • l'outil lit un fichier text.txt, sépare chaque ligne en mots, et crée un dictionnaire avec, pour chaque mot, un compte du nombre d'occurrences de ce mot. On peut présumer que tous les mots sont en minuscules et qu'il n'y a pas de ponctuation.
  • l'outil demande à l'utilisateur de donner un mot, après lequel le programme retourne le nombre d'occurrences de ce mot, et continue d'offrir la possibilité de demander un autre mot.

Séparez le programme en fonctions, avec au moins

  • une fonction create_dictionary(name) pour lire le fichier name et créer le dictionnaire avec, pour chaque mot, le nombre d'occurrences;
  • une autre fonction ask(name) pour demander les mots à l'utilisateur qui sont stockés dans le fichier name.

Pour simplifier l'exercice, il n'est pas nécessaire de traiter les erreurs.


        
        

Écrivez une fonction table(filename_in, filename_out, width) qui crée pour un fichier donné un autre fichier dans lequel toutes les lignes ont été mises dans un tableau. Pour cet exemple:

Mons
Bruxelles
Ottignies
Jean Charles

le résultat avec width = 8 doit être:

::
Mons Bruxelle Ottignie Jean Cha

Remarquez qu'il y a un espace avant et après chaque ligne. Considérez l'utilisation des méthodes suivantes de string:

  • la méthode format
  • la méthode rstrip

Consultez la documentation de Python si vous ne connaissez pas encore ces méthodes. Vous pouvez présumer que le fichier filename_in existe.


        
        

Toute votre vie vous vous êtes demandé "Où cette stupide chouette a-t-elle égaré ma lettre ?", "Quand irais-je enfin à Poudlard ?" ou même à la fin "Suis-je un Cracmol ?". Ne vous inquiétez pas!

Poudlard vous a enfin contacté pour une tâche importante. Même si vous êtes trop vieux pour apprendre la sorcellerie, ils ont de la chance parce que vous avez appris une différente sorte de magie : la programmation.

Ils ont décidé de moderniser un peu leurs services d'admission et veulent que vous créiez un programme qui sera capable de remplir un fichier (template d'un lettre d'admission) avec le nom de l'étudiant. De cette manière, ils pourront réduire le coût en plumes et réduire la charge de travail des elfes!

Implémentez la fonction write(letter_template, name) en Python.

N'oubliez pas de lever une exception si elle se produit.


        
        

Les règles du Quidditch ont été établie en 1750 par le Département des jeux et sports magiques. Et il n'est dit nul part que l'arbitre ne peut recevoir un petit coup de main.

Madame Bibine est plutôt occupée à regarder pour le boutenchoc, le croc-en-manche, le hochequeue et tout un tas d'autres vilaines fautes de Quidditch. Donc elle a pensé que vous pourriez écrire une programme qui déciderait le vainqueur d'un match en se basant sur la liste des points.

La liste des scores serait fournie dans un fichier. Le contenu de ce fichier suivrait le format suivant :

  • Les deux premières lignes : Noms des équipes
  • Les lignes qui suivent : Team_scoring points

S'il y a une erreur, pensez à lever une exception.

Rappelez-vous qu'attraper le vif d'or en plus de rapporter 150 points marque la fin du match.

Implémentez la fonction referee(score_file) en Python.


        
        

Pour votre prochain gros jeu, Dieu de la Destruction Massive : Edition Jeu du Siècle, vous devez créer une fonction pour charger et sauvegarder les données du joueur.

Vous devez créer deux fonctions : une pour sauvegarder les données et une pour les charger. Vous êtes libres d'enregistrer les données comme vous le souhaitez dans le fichier, mais placer un entier par ligne est probablement la méthode la plus simple. S'il n'y a pas de fichier à charger quand vous voulez utiliser le fontion load_data (par exemple, le joueur commence un nouveau jeu), vous devez lever une FileNotFoundError.

Les deux fonctions auront ces définitions :

#sauvegarder les 4 entiers dans le fichier nommé filename
def save_data(filename, life, mana, position_x, position_y)

#retourne un tuple contenant les valeurs (life, mana, position_x et position_y précédemment sauvegardées
def load_data(filename)


        
        
<string>

Table des matières

Mission 7 - Dictionnaires

Mission 7 : Dictionnaires

Mission 7 : Dictionnaires

Introduction

Le but de cette mission est de développer un outil qui permet un utilisateur de chercher répétitivement dans un fichier de texte: pour des mots donnés, l'outil va imprimer les phrases dans lesquelles tous les mots donnés sont présents. Pour assurer que l'outil ne prend pas trop de temps pour déterminer ces phrases, on va construire un index des mots présents dans les phrases des documents. On utilisera les dictionnaires pour stocker l'index.

Objectifs

Objectifs individuels

A l’issue de ce problème, chacun d’entre vous sera en mesure d’exploiter les notions suivantes :
  • dictionnaires
  • fichiers

Préparation, étude et apprentissage

La matière relative à cette mission est décrite dans les sections suivantes du syllabus en ligne :

Questionnaire de démarrage

Questions à choix multiple

Les questions à choix multiples de cette mission sont également accessibles en ligne depuis https://inginious.info.ucl.ac.be/course/LSINF1101-PYTHON/Session7_QCM


        
        

Question 1

Considérez le code suivant:

codes = {"Bruxelles" : [1000,1020,1030], "Louvain-la-Neuve" : [1348], "Wavre": [1300,1301]}

Les morceaux de code ci-dessous sont executés chacun après ce code. Décrivez ce qui se passe pour chacun des cas.

  • On exécute :
print(codes["Bruxelles"])
 
 

  • On exécute :
print(codes["Mons"])
 
 

  • On exécute :
print(codes[1000])
 
 

  • On exécute :
print(codes.get("Mons",[]))
 
 

  • On exécute:
codes["Liege"] = [4000]
print(codes)
 
 

  • On exécute:
codes["Bruxelles"].append(1040)
print(codes)
 
 

  • On exécute:
codes.get("Bruxelles",[]).append(1050)
print(codes)
 
 

  • On exécute:
codes.get("Arlon",[]).append(8362)
print(codes)
 
 

  • On exécute:
if "Bruxelles" in codes:
  print("Found!")
else:
  print("Not found!")
 

  • On exécute:
if 1000 in codes:
  print("Found!")
else:
  print("Not found!")
 

  • On exécute:
for x in codes:
  print(x)
 
 
 

  • On exécute:
for x in codes:
  print(codes[x])
 
 
 

  • On exécute:
for x in codes.items():
  print(x)
 
 

  • On exécute:
for x, y in codes.items():
  y = y + [2000]
print(codes)
 
 

  • On exécute:
for x, y in codes.items():
  y.append(2000)
print(codes)
 
 

  • On exécute:
for x, y in codes.items():
  x = x + "*"
print(codes)
 
 

Question 2

Considérez le code suivant:

def mot_ligne(ligne):
    d = {}
    for mot in ligne:
        d[mot] = 1
    return d

Quelle est la taille du dictionnaire résultant des appels suivants ? Pourquoi ?

  • mot_ligne(["the","world","goes","round"])
  • mot_ligne(["the","world","and","the","galaxy"])
  • mot_ligne(["run","run","run"])

Question 3

Écrivez une fonction avec la spécification suivante:

def create_index ( list_of_words ):
    """ crée un index pour une liste de chaînes de caractères.
        L'index se compose d'un dictionnaire dans lequel pour chaque
        chaîne de caractères dans list_of_strings on retrouve une
        liste des positions où l'on retrouve cette chaîne de
        caractères.

        Par exemple, pour la liste

          ["the","galaxy","and","the","universe","are","the","same"]

        Le résultat est

          {"the":[0,3,6],"galaxy":[1],"and":[2],"universe":[4], \
           "are":[5],"same":[7]}

    Args:
        list_of_words: une liste de chaînes de caractères
    Retourne:
        un dictionnaire avec pour chaque mot dans la liste,
        une liste des positions de cette chaîne de caractères
        dans la liste
    """


        
        

Question 4

Étant donnée:

  • une matrice representée en utilisant des listes imbriquées
  • une matrice representée en utilisant un dictionnaire, où les zéros ne sont pas stockées.

Par exemple,

l = [ [ 0, 2, 4 ], [ 4, 1, 0 ] ]
d = { (0,1): 2, (0,2): 4, (1,0): 4, (1,1): 1 }

Écrivez une fonction equal(l,d) qui détermine si d contient les même valeurs pour chaque élément de l. (Nous permettons que d soit plus large que l.)


        
        

Question 5

Étant donné une structure de données comme la suivante:

System Message: ERROR/3 (<string>, line 420)

Content block expected for the "code-block" directive; none found.

.. code-block:: python

l = [{"City": "Bruxelles", "Country": "Belgium"},
{"City": "Berlin", "Country": "Germany"}, {"City": "Paris", "Country": "France"}]

Écrivez une fonction get_country(l,name) qui, pour le nom d'une ville name et une structure de données l du format illustré dans l'exemple, retourne le nom du pays dans lequel la ville est localisée. La fonction retourne None si la ville n'est pas dans l.


        
        

Mission 7

Mission 7

Le but de cette mission est de contribuer à un outil qui permet un utilisateur de chercher répétitivement dans un fichier de texte.

Il faut implementer les fonctions suivantes dans un fichier search.py et vérifier que ces fonctions sont correctes:

  • La fonction readfile(filename) avec la spécification suivante:

    def readfile(filename):
        """ Crée une liste des lignes contenues dans un fichier dont le nom est ``filename``
    
        Args:
            filename: le nom d'un fichier de texte
        Retourne:
            une liste dans laquelle chaque ligne du fichier filename est un élément.
            Si filename n'existe pas, la fonction retourne une liste vide.
        """
    
  • La fonction get_words(line) avec la spécification suivante:

    def get_words(line):
        """ Pour une chaîne de caractères donnée, retourne une liste des mots dans
            la chaîne en minuscules et dans l'ordre d'apparence dans le texte. La
            ponctuation et les caractères non-alphabétiques doivent être ignorés et
            retirés des mots.
    
            Par exemple :
                - Pour la chaîne de caractères :
                    "Turmoil has engulfed the Galactic Republic. The taxation of
                    trade routes to outlying star systems is in dispute."
                  Le résultat est :
                    ["turmoil", "has", "engulfed", "the", "galactic", "republic",
                    "the", "taxation", "of", "trade", "routes", "to", "outlying",
                    "star", "systems", "is", "in", "dispute" ]
                - Pour la chaîne de caractères :
                    "These aren't the droids you're looking for."
                  Le résultat est :
                    ['these', 'arent', 'the', 'droids', 'youre', 'looking', 'for']
    
            Un caractère est considéré comme une ponctuation ou un
            caractère non-alphabétique si ce n'est pas une lettre, selon la
            fonction string.isalpha().
    
        Args:
            line: une chaîne de caractères.
        Retourne:
            une liste des mots dans la chaîne, en minuscules, et sans ponctuation.
        """
    

    Ici, vous pouvez utiliser la méthode string.isalpha(); un exemple de l'utilisation de cette méthode se trouve ci-dessous:

    text = "a.b"
    r = ""
    for c in text:
      if c.isalpha():
        r += c
    print(r)  # "ab"
    
  • La fonction create_index(filename) avec la spécification suivante:

    def create_index(filename):
        """ crée un index pour le fichier avec nom ``filename``. L'index se compose
            d'un dictionnaire dans lequel pour chaque mot du fichier ``filename``
            on retrouve une liste des indices des lignes du fichier qui contiennent
            ce mot.
    
            Par exemple, pour un fichier avec le contenu suivant:
    
              While the Congress of the Republic endlessly debates
              this alarming chain of events, the Supreme Chancellor has
              secretly dispatched two Jedi Knights.
    
            Une partie de l'index, representé comme dictionnaire, est:
    
    
              {"while": [0], "the": [0,1], "congress": [0], \
               "of": [0,1], "republic": [0], ... , "jedi": [2], ...}
    
        Args:
            filename: une chaîne de caractères
        Retourne:
            un dictionnaire avec pour chaque mot du fichier (en minuscules)
            la liste des indices des lignes qui contiennent ce mot.
        """
    

    Cette fonction doit utiliser les fonctions get_words et readfile.

  • La fonction get_lines(words,index) avec la spécification suivante:

    def get_lines(words, index):
       """ Détermine les lignes qui contiennent tous les mots indexes dans ``words``,
           selon l'index ``index``.
    
           Par exemple, pour l'index suivant:
    
             index = {"while": [0], "the": [0,1], "congress": [0], \
                      "of": [0,1], "republic": [0], ... , "jedi": [2], ...}
    
           La fonction retourne
             get_lines(["the"], index) -> [0, 1]
             get_lines(["jedi"], index) -> [2]
             get_lines(["the", "of"], index) -> [0, 1]
             get_lines(["while", "the"], index) -> [0]
             get_lines(["congress", "jedi"], index) -> []
             get_lines(["while", "the", "congress"], index) -> [0]
    
       Args:
           words: une liste de mots, en minuscules
           index: un dictionnaire contenant pour mots (en minuscules) des listes de nombres entiers
       Retourne:
           une liste des nombres des lignes contenant tous les mots indiqués
       """
    

    Commencez par faire cette fonction uniquement pour les listes avec un mot; dans ce cas, l'outil marche au moins quand l'utilisateur spécifie un seul mot. Essayez de modifier cette fonction pour les listes plus longues ensuite.

    Plusieurs approches sont possible pour calculer le résultat de get_lines() pour des listes de mots plus longues. Une possibilité est de traverser la liste associé au premier mot, et de vérifier si on trouve dans ces lignes aussi les autre mots, en utilisant l'index de chaque mot.

De nouveau, les fonctions ci-dessus doivent être mises en oeuvre dans un fichier search.py.

L'outil est implementé dans un fichier utility.py, qui importe le fichier search.py. Voici le code de utility.py, que vous pouvez soumettre sans le modifier:

import search

filename = input("Spécifiez le nom de fichier: ")
index = search.create_index(filename)
while True:
  words = input("Spécifiez les mots a rechercher, en utilisant des espaces entre les mots: ")
  lines = search.get_lines(words.strip().split(), index)
  print("Les mots se retrouvent dans ces lignes:")
  for line in lines:
    print(line)

Autrement dit, après avoir demandé le nom d'un fichier, dans une boucle, l'interface demande à l'utilisateur de donner une liste de mots; chaque fois, l'outil cherche les lignes dans lesquelles les mots spécifiés sont présents, et imprime ces lignes. Votre tâche principale est de vous assurer que l'outil fonctionne correctement, en mettant en oeuvre les fonctions dans le fichier search.py.

Pour vous aider, vous trouverez un exemple de texte episodeIV_dialogues.txt.

Créez les fonctions dans l'ordre spécifié. Si vous n'arrivez pas à terminer toutes les fonctions, soumettez les fonctions que vous avez réussi à terminer.

Pour assurer que l'outil marche correctement, vous devez ajouter des tests pour vérifier que les fonctions sont correctes; par exemple, les tests pour la fonction get_words doivent être mis dans une fonction test_get_words. Puisque vous devez tester une fonction qui lit un fichier, créez des petits fichiers pour tester cette fonction; il faut soumettre ces fichiers de texte aussi.

Les tests doivent être mis dans un fichier test.py qui importe search.py. Un petit exemple du contenu du fichier test.py est:

import search


def test_get_words():
  assert search.get_words("Turmoil has engulfed the Galactic Republic.") == ["turmoil", "has", "engulfed", "the", "galactic", "republic"], "Petit exemple donné"

test_get_words()

Si vous le souhaitez, vous pouvez étendre l'outil même, par exemple, pour montrer les lignes au lieu des nombres des lignes. Dans ce cas vous pouvez modifier le code du fichier utility.py. Indiquez ceci dans le commentaire de utility.py.

Remise de votre solution

Pour cette mission, vous devez soumettre:

  • un fichier search.py ;
  • un fichier utility.py (éventuellement non modifié en comparaison avec le code donné ci-dessus);
  • un fichier test.py avec les tests (qui étendent l'exemple donné ci-dessus);
  • 2 petits fichiers de texte que vous utilisez dans vos tests
  • un fichier README

        
        
Questions complémentaires

Questions complémentaires

Lors de la dernière session du club de duel, les sabliers comptant les points de chaque maison ont été détruits même un reparo n'a rien pu faire et la célébration de la Coupe des Quatre Maisons arrive à grands pas!

Heureusement, Rusard, qui ne fait pas confiance à la magie, a gardé les comptes de tous les accomplissements perpétrés par les étudiants. Il vous a fourni un dictionnaire associant chaque élève à sa maison et un parchemin avec tous leurs gains.

La liste des scores est donnée dans un fichier. Le contenu de ce fichier suit le format suivant :

  • Lignes: student_name points

Merci de retourner le nom de la maison gagnante, dans le cas d'un ex-aequo : retournez une liste des meilleures maisons.

S'il y a une erreur, levez une exception.

Implémentez la fonction winning_house(scroll) en Python.

Vous avez déjà la liste des étudiants triés par maison à votre disposition :

students = {'gryffindor': ['Harry', 'Hermione', 'Ron', 'Ginny', 'Fred', ' Georges', 'Neville'],
            'ravenclaw': ['Cho', 'Luna', 'Sybill', 'Marcus', 'Marietta', 'Terry', 'Penelope'],
            'hufflepuff': ['Pomona', 'Zacharias', 'Teddy', 'Cedric', 'Nymphadora', 'Newton', 'Justin'],
            'slytherin': ['Malfoy', 'Severus', 'Dolores', 'Horace', 'Blaise', 'Pansy', 'Bellatrix']}


        
        

Anonymous a été épaté par votre travail et a décidé de vous faire confiance pour l'analyse de toutes les données qu'ils ont intercepté.

Avec l'aide des deux fonctions que vous avez déjà créées, vous allez transformer chaque ligne de données en un pattern et extraire le nombre d’occurrences présentes dans le fichier.

Créez une fonction collect(data) pour lire le fichier, extraire les patterns et les enregistrer dans un dictionnaire avec leurs occurrences.

S'il y a une erreur, levez une exception.

Rappel:

  • extract(code): donne la nature de chaque élément d'une string.
  • treatment(code): transforme une suite d'éléments en un pattern.


        
        

Après la troisième guerre mondiale, la planète est laissée dans un état post-apocalyptique. Vous êtes l'un des seuls survivants et vous cherchez un peu de compagnie. Mais vous ne pouvez pas trop swiper sur Tinder vu que le réseau est mort..

Heureusement votre meilleur ami est avec vous... Votre ordinateur (oui, ça craint!) Avec son aide, aide vous allez pouvoir entrer en contact avec le reste du monde. Puisque vous avez un dictionnaire Morse enregistré sur votre machine (Matt Damon avait bien une table ASCII avec lui dans "Seul sur Mars" , donc c'est pas si absurde), vous allez l'utiliser pour traduire votre texte et l'émettre grâce à une vieille radio.

Notez que si vous devez essayer de traduire un caractère non-enregistré, vous devez lever une exception TypeError.

Implémentez la fonction translate(data) en Python.

Avec data comme chaine de caractère que vous voulez encoder en Morse et un dictionnaire morse utile pour faire les traductions.

morse = {
"A" : ".-",
"B" : "-...",
"C" : "-.-.",
"D" : "-..",
"E" : ".",
...
}


        
        

Votre tinder par radio a bien fonctionné et vous pouvez désormais discuter avec beaucoup de gens intéressants. Encore plus intéressant, une merveilleuse créature vient de vous contacter et est parvenue à vous envoyer une image à travers des points et des espaces (Dieu bénisse le code Morse).

Vous voulez vraiment lui parler ainsi qu'à vos autres futurs matchs mais vous venez de réaliser que vous n'avez jamais bien étudier les langues étrangères. Heureusement, vous avez des dictionnaires sur votre ordinateur (qui a apparemment téléchargé l'entierté d'internet). Vous devez simplement coder un traducteur!

Notez que si un mot que vous voulez traduire n'est pas dans le dictionnaire, vous devez laisser le mot dans son langage original.

Exemple:

"I'm fond of Dean" deviendrait en français avec le dictionnaire fr: "je suis amoureux de doyen" Notez qu'on ne s'attend pas à ce que vous donniez des traductions exactes mais bien une traduction mot par mot. De plus, les clés sont enregistrées en minuscules dans le dictionnaire.

Implémentez la fonction translate(data, lan) en Python.

Avec data comme la chaine de caractère que vous souhaiter traduire et les dictionnaires nommés selon lan utilisable pour faire les traductions dans le langage ciblé.


        
        

Vous et vos amis vous prêtez souvent de l'argent. Plutôt que d'utiliser une application spéciale pour se rappeler qui doit combien d'argent et à qui, vous décidez de faire votre propre programme python pour réaliser cette tâche.

Spécifiquement, vous aimeriez pouvoir:

  • dire qui doit combien d'argent à qui;
  • changer les comptes quand quelqu'un rembourse ou prête de l'argent à un autre;
  • ajouter une personne qui emprunte et/ou rembourse de l'argent;
  • calcule la somme de tout l'argent emprunté à ce moment précis.

Notez que de l'argent prêté à quelqu'un doit être emprunté. En d'autres termes, si Woody a prêté 3€ à Buzz, votre programme devrait dire que Buzz doit 3€ à Woody et que Woody doit -3€ à Buzz.

Pour faire cela, vous allez utiliser un dictionnaire de dictionnaires appelé borrowed_money, indexé par le nom des personnes (comme des strings). Le premier index sera le nom de "l'emprunteur"; le deuxième, celui du "prêteur".

Par exemple, si Woody a prêté 3€ à Buzz, votre dictionnaire devrait être comme suit:

borrowed_money[\"Buzz\"][\"Woody\"] == 3  # Lisez \"Buzz doit 3€ à Woody\"
borrowed_money[\"Woody\"][\"Buzz\"] == -3

Par conséquent, vous pouvez obtenir un dictionnaire qui contient tout l'argent que Buzz emprunte:

borrowed_money[\"Buzz\"] == {\"Woody\": 3, \"Hamm\": 60, \"Rex\": -5}

Faites une fonction give_money(borrowed_money, from_person, to_person, amount) qui sera appelée quand from_person donne amount € à to_person (soit parce que from_person prête de l'argent to_person, ou bien parce qu'il rembourse de l'argent qu'il a emprunté). Si une des deux personnes n'est pas déjà une clé dans le dictionnaire, elle doit y être ajoutée. Vous devez lever une ValueError dans le cas où quelqu'un essaye de se donner de l'argent à lui-même.

Faites une autre fonction total_money_borrowed(borrowed_money) qui retourne le montant total d'argent emprunté en ce moment (c'est-à-dire, la somme des montants positifs se trouvant dans le dictionnaire).

Note: vous devez lever une ValueError``*si l'un des arguments passé à ces fonctions est invalide (c'est-à-dire si les noms ne sont pas de strings, si* ``borrowed_money n'est pas un dictionnaire ou si le montant d'argent n'est pas un integer ou un float). Vous pouvez tester si une variable est du bon type des manières suivantes :

variable = 5
type(variable) == int  # retourne True
# OR
isinstance(variable, int)  # retourne True

Enfin, implémentez l'exemple où Mark prête 2 000 000 € à Bill et Steve, Serguei prête 5 000 000 € à Bill, Bill prête 6 000 000 € à Larry et enfin, Larry prête 5,5 € à Linus. Ensuite, Steve rembourse Mark. Utilisez la variable borrowed_money.


        
        
<string>

<string>

Table des matières

Mission 8 - Classes et objets

Mission 8 : Classes et objets

Mission 8 : Classes et objets

1   Introduction

L'informatique et l'internet ont révolutionné le monde de la diffusion musicale. Grâce à la numérisation et aux connexions à haut débit, chacun peut de nos jours stocker et échanger très facilement de larges volumes de musique. La vente en ligne a détrôné les magasins physiques, les ventes de disques sont en chute libre et les logiciels sont désormais au centre de la diffusion musicale, que ce soit dans les serveurs des diffuseurs, sur nos ordinateurs et sur les baladeurs et smartphones dans nos poches.

Spotify, un service logiciel d'écoute musicale bien connu.

Fondé par de jeunes diplômés de l'UCL, la société SoundPlaza compte mettre en place un espace de rencontre pour les musiciens de la région, avec une forte présence sur la Toile. Ils veulent offrir un site de diffusion de musique pour leurs membres et font appel à votre service pour les aider à développer leur infrastructure de gestion de données. Ils désirent, à partir de la liste des chansons disponibles sur leur serveur, assembler automatiquement des albums correspondant à la taille d'un CD. Ils comptent sur vos compétences nouvellement acquises en programmation orientée objets pour définir et exploiter les structures de données nécessaires.

Depuis le début de ce cours, vous avez commencé à manipuler des classes et objets déjà définis (comme les classes str, int, float et Turtle, par exemple). Néanmoins, cette mission marque votre entrée dans le vrai monde de la programmation orientée objets. Cette semaine, vous allez définir vos propres classes et objets.

2   Objectifs

A l'issue de cette mission, chacun d'entre vous :

  • pourra expliquer en ses propre mots en quoi consiste la programmation orientée objets;
  • pourra expliquer et illustrer les notions élémentaires de la programmation orientée objets telles que:
    • classe, objet et instance;
    • attributs et méthodes d'instance;
    • méthode d'initialisation et constructeur;
  • pourra faire des manipulations simple sur un objet comme :
    • la création d'un objet;
    • accéder à un de ces attributs;
    • modifier la valeur d'un attribut;
    • appeler une méthode sur cet objet;
  • aura appris la conversion automatique d'un objet en un string par la méthode magique __str__;
  • aura écrit un premier programme utilisant des objets en Python;

3   Préparation, étude et apprentissage

La matière relative à cette mission est décrite dans les sections suivantes de la partie Objects du syllabus en ligne:

  • 1 - Classes and objects - Basics
    • Object-oriented programming
    • User-defined compound data types
    • Attributes
    • Improving the initialiser
    • Adding other methods to the class
    • Instances as arguments and parameters
    • Converting an instance to a string
    • Instances as return values
    • A change of perspective
    • Objects can have state
  • 2 - Classes and objects - Advanced
    • Rectangles
    • Objects are mutable
    • Sameness
    • Copying

Un exemple d'un un premier programme utilisant des objets en Python, utlisé comme illustration dans le cours théorique, se trouve dans l'annexe suivant:

4   Questionnaire de démarrage

4.1   Questions à choix multiple

Les questions à choix multiples de cette mission sont accessibles en ligne depuis https://inginious.info.ucl.ac.be/course/LSINF1101-PYTHON/Session9_QCM


        
        

4.2   Questions ouvertes

4.2.1   Définitions

Considérez le code suivant d'une classe Student représentant un étudiant:

class Student :

    def __init__(self,n) :
        """
        Initialise un nouvel objet de type Student avec un nom n donné.
        @pre:  -
        @post: Un objet de type Student a été créé avec comme 'name' n,
               et un score None pour chacun des trois tests 'test1', 'test2' et 'test3'
        """
        # nom de l'étudiant
        self.name = n
        # score reçu par l'étudiant sur trois tests
        # (initialement None car l'étudiant n'a pas encore passé les tests)
        self.test1 = None
        self.test2 = None
        self.test3 = None

    def average_score(self) :
        """"
        Calcul de la moyenne des scores obtenus par l'étudiant sur les 3 tests.
        @pre: les variables d'instance test1, test2 et test3
              contiennent des valeurs de type int
        @post: retourne la moyenne de ces trois valeurs
        """
        return (self.test1 + self.test2 + self.test3) / 3

Les instructions suivant donnent un exemple de comment cette classe peut être utilisé:

student = Student("Kim")
student.test1 = 14.0
student.test2 = 10.5
student.test3 = 12.0
print("Bonjour, " + student.name + ". Vos scores sont:")
print(student.test1)
print(student.test2)
print(student.test3)
print("La moyenne de vos scores est " + str(student.average_score()))
student2 = student
print("La moyenne de vos scores est " + str(student2.average_score()))
student = None
student2 = None

Sur base de ces extraits, donnez des exemples des notions suivantes, en veillant à être précis et rigoureux dans votre formulation:

**Classe, objet (ou instance)**
 
 
 
 
 
 
 
**Constructeur et méthode d'initialisation**
 
 
 
 
 
 
**Attribut (ou variable d'instance)**
 
 
 
 
 
**Méthode d'instance**
 
 
 
 
**Référence à un objet et la valeur None**
 
 
 
 
**Référence à self**
 
 
 
 

4.2.2   Classes et objets

Dans la question précédente, expliquez les notations student.name, student.average_score() et self.name et leur interprétation par Python.

 
 
 
 
 
 
 
 

4.2.3   Méthode de conversion de string

Dans la première question, pour imprimer le détail d'un objet student de la classe Student on devait exécuter la série d'instructions suivante:

print("Bonjour, " + student.name + ". Vos scores sont:")
print(student.test1)
print(student.test2)
print(student.test3)
print("Votre score moyenne est " + str(student.average_score()))

Au lieu d'exécuter cette série d'instructions à l'extérieur de la classe, ce serait beaucoup plus facile de pouvoir obtenir le même résultat en écrivant seulement:

print(student)

A cette fin, ajoutez une méthode magique __str__ à la classe Student qui retourne un string du style:

"Bonjour, Kim. Vos scores sont:
 14.0
 10.5
 12.0
 Votre score moyenne est 12.166666666666666"

Tester votre code comme suite:

>>> student = Student("Kim")
>>> student.test1 = 14.0
>>> student.test2 = 10.5
>>> student.test3 = 12.0
>>> print(student)
Bonjour, Kim. Vos scores sont:
14.0
10.5
12.0
Votre score moyenne est 12.666666666

4.2.4   Création de classes


        
        

4.2.5   Une classe simple

Dans le cadre d'un cours de programmation, un étudiant a développé une classe Pair permettant de manipuler un objet contenant une paire d'entiers. Le code de cette classe Python est repris ci-dessous :

class Pair:
    """
    Une paire d'entiers
    """

    def __init__(self, x=None, y=None):
        """
        @pre -
        @post crée une paire (a,b) composée de x et y,
              ou une paire non-initialisée si aucune valeur
              de x et de y n'est donné lors de l'appel au constructeur
        """
        self.a = x   # le premier élément de la paire
        self.b = y   # le second élément de la paire

    def __str__(self):
        return str(self.a) + ", " + str(self.b)

Remarque: La notation x=None, y=None dans l'entête de la méthode __init__ permet de donner des valeurs par défaut à certains ou à tous paramètres de la fonction. Lorsque nous appelons la fonction, si des valeurs ne sont pas données pour ces paramètres, ils reçoivent les valeurs par défaut sinon, on peut leur donner une valeur différente en donnant un argument lors de l'appel.

Considérons maintenant le code Python ci-dessous illustrant une utilisation de la classe Pair:

p0 = Pair()      ##1##
p1 = Pair(0,0)   ##2##
p2 = Pair(1,1)   ##3##
p0.b = 3         ##4##
p1.a = 10        ##5##
p2.a = p1.a      ##6##
p2 = p1          ##7##

Expliquez les opérations effectuées par chacune de ces lignes. Pensez à utiliser une représentation graphique des différents objets telle que celle utilisée dans le syllabus ou les transparents en indiquant les valeurs des différentes variables d'instance.

 
 
 
 
 
 
 
 
 
 
 
 
 
 

Après avoir exécuté les opérations précédentes, qu'impriment les instructions suivantes?

print(p0)        ##8##
print(p1)        ##9##
print(p2)        ##10##
 
 
 

4.2.6   Egalité

Considérez les instructions suivantes qui utilisent la classe Pair vue précédemment:

p1 = Pair(9, 42)
p2 = Pair(9, 42);
if (p1 == p2) : print("Egaux en 1")   ##1##
p2 = p1
if (p1 == p2) : print("Egaux en 2")   ##2##

Lesquelles des lignes ##1## et/ou ##2## produiront-elles un message? Pourquoi? Expliquez ce comportement avec un dessin.

 
 
 
 

4.2.7   Une méthode simple


        
        

4.2.8   OrderedPair

Un étudiant propose ensuite de construire une classe OrderedPair qui utilise la classe Pair définie précédemment et y ajoute un booléen. Ce booléen est utilisé pour indiquer si une instance de la classe OrderedPair est ordonnée ou non: il est vrai lorsque la valeur stockée dans l'attribut a est inférieure ou égale à la valeur stockée dans l'attribut b.


        
        

Mission 8

Mission 8

1   Introduction

L'objectif principal de cette mission est de définir et d'utiliser trois classes correspondant respectivement à une durée (une espace de temps sous la forme heures-minutes-secondes), à une chanson (caractérisée par un titre, un auteur et une durée) et à un album (un ensemble de chansons). Vous utiliserez ensuite ces classes pour réaliser la génération d'albums souhaitée. Vous travaillerez par groupes de deux.

Dans le cadre du prototype à réaliser, les chansons vous sont fournies dans un fichier contenant des lignes de texte:

"TITRE AUTEUR MIN SEC"

où "TITRE", "AUTEUR", "MIN" et "SEC" correspondent respectivement au titre, à l'auteur, et à la durée de la chanson en minutes et secondes, et ne contiennent eux-mêmes pas d'espaces, par exemple:

Let's_Dance David_Bowie 4 5
Relax Frankie_Goes_To_Hollywood 3 54
Purple_Rain Prince 5 48
Enjoy_The_Silence Depeche_Mode 4 13

Ce format facilite leur lecture. On vous rappelle que la méthode split() permet de séparer un string contenant des espaces en mots individuels.

Il est plus que jamais important de bien tester votre code, étant donné que les classes que vous définissez pourront être utilisées dans des usages multiples. Au sein de votre binôme, pendant qu'un étudiant se concentre sur le développement d'une classe, l'autre pourrait préparer les tests pour cette classe. Les spécifications des méthodes étant donné par avance, il est en effet tout à fait possible de préparer des tests en même temps que (voire avant) la classe à tester. Il s'agit en quelque sorte d'un jeu: le développeur parviendra-t-il à écrire une classe qui fonctionnera correctement sous toutes les attaques du testeur? Le testeur parviendra-t-il à trouver le test qui causera un fonctionnement incorrect?

Remarque: Lors de cette mission vous utiliserez encore les instructions 'assert' pour tester votre programme orienté objet. Dans une mission futur nous introduirons le mécanisme des 'tests unitaires' qui sera encore mieux approprié pour tester du code orienté objets.

2   Etapes

2.1   Fichiers

Chargez les fichiers "music-db.txt", "mission8.py" et "test.py".

  • "music-db.txt" contient une liste de plus de 300 chansons, au format décrit ci-dessus.
  • "mission8.py" contient la définition des 3 classes Duree, Chanson et Album à compléter, mais avec une implémentation vide.
  • "test.py" contient une ébauche (à compléter par vous) d'un ensemble de fonctions test pour tester le bon comportement des 3 classes et du programme à réaliser.

2.2   La classe Duree

Commencez par définir la classe Duree qui représente une durée exprimée en heures (h), minutes (m) et secondes (s).

Ajoutez d'abord la méthode d'initialisation __init__(self, h, m, s), qui requiert que m et s soient dans l'intervalle [0..60[ et crée un nouveau temps de h heures, m minutes et s secondes. Ajoutez une spécification à cette méthode et vérifiez que les conditions requises soient bien respectées.

def __init__(self,h,m,s):
    """
    @pre: h, m et s sont des entiers positifs (ou zéro)
          m et s sont < 60
    @post: Crée une nouvelle durée en heures, minutes et secondes.
    """

Ajoutez ensuite les méthodes correspondant aux spécifications suivantes:

def to_secondes(self):
    """
    @pre:  -
    @post: Retourne le nombre total de secondes de cette instance de Duree (self).
    Par exemple, une durée de 8h 41m 25s compte 31285 secondes.
    """

def delta(self,d) :
    """
    @pre:  d est une instance de la classe Duree
    @post: Retourne la différence en secondes entre cette durée (self)
           et la durée d passée en paramètre.
           Cette valeur renovoyée est positif si cette durée (self)
           est plus grand que la durée d, négatif sinon.
    Par exemple, si cette durée (self) est 8h 41m 25s (donc 31285 secondes)
    et la durée d est 0h 1m 25s, la valeur retournée est 31200.
    Inversement, si cette durée (self) est 0h 1m 25s et la durée
    d est 8h 41m 25s, alors la valeur retournée est -31200.
    """

def apres(self,d):
    """
    @pre:  d est une instance de la classe Duree
    @post: Retourne True si cette durée (self) est plus grand que la durée
           d passée en paramètre; retourne False sinon.
    """

def ajouter(self,d):
    """
    @pre:  d est une instance de la classe Duree
    @post: Ajoute une autre durée d à cette durée (self),
           corrigée de manière à ce que les minutes et les secondes soient
           dans l'intervalle [0..60[, en reportant au besoin les valeurs
           hors limites sur les unités supérieures
           (60 secondes = 1 minute, 60 minutes = 1 heure).
           Ne retourne pas une nouvelle durée mais modifié la durée self.
    """

def __str__(self):
    """
    @pre:  -
    @post: Retourne cette durée sous la forme de texte "heures:minutes:secondes".
    Astuce: l'expression "{:02}:{:02}:{:02}".format(heures, minutes, secondes)
    retourne le string désiré avec les nombres en deux chiffres en ajoutant
    les zéros nécessaires.
    """

2.3   Tester la classe Duree

Dans le fichier test.py, ajoutez ou complétez au fur et à mesure des fonctions tests pour tester la classe Duree. Exécutez ces tests régulièrement et assurez-vous que les résultats sont conformes aux spécifications, en corrigeant au besoin.

Il est une bonne idée d'avoir un ou plusieurs tests, avec différents scénarios de test, par méthode de la classe Duree. Par exemple, pour la méthode ajouter() de votre classe Duree, vous pourrez implémenter une fonction test_Duree_ajouter() pour tester les différents scénarios d'utilisation de la méthode ajouter() de cette classe. Vous pouvez vous inspirer des quelques tests qui se trouvent déjà dans le fichier test.py.

2.4   La classe Chanson

Définissez maintenant la classe Chanson représentant une chanson, caractérisée par un titre t (string), un auteur a (string) et une durée d (Duree). Implémentez la méthode d'initialisation __init__ ainsi que la méthode de conversion __str__ correspondant aux spécifications suivantes:

 def __init__(self,t,a,d):
     """
     @pre:  t et a sont des string, d est une instance de la classe Duree
     @post: Crée une nouvelle chanson, caractérisée par un titre t,
            un auteur a et une durée d.
     """

def __str__(self):
    """
    @pre:  -
    @post: Retourne un string décrivant cette chanson sous le format
           "TITRE - AUTEUR - DUREE".
           Par exemple: "Let's_Dance - David_Bowie - 00:04:05"
    """

2.5   Tester la classe Chanson

Ajoutez au fichier test.py une série de tests pour tester les différentes méthodes de la classe Chanson.

2.6   La classe Album

Définissez maintenant la classe Album représentant un album contenant une ou plusieurs chansons.

Implémentez d'abord la méthode d'initialisation __init__ pour créer un album vide:

def __init__(self, numero):
    """
    @pre:  numero est un entier identifiant de facon unique cet album
    @post: Crée un nouvel album, avec comme identifiant le numero,
           et avec une liste de chansons vide.
    """

Implémentez également une méthode add(self,chanson) pour ajouter une chanson à un album. Cette méthode retourne False et ne modifie rien si lors de l'ajout de la chanson l'album aurait atteint 100 chansons ou sa durée aurait dépassé 75 minutes. Sinon la chanson est rajoutée à la fin de la liste des chansons de cet album, la durée totale de l'album est augmentée avec la durée de la chanson, et la méthode add retourne True.

Finalement, implémentez la méthode de conversion __str__ pour imprimer la description d'un album selon le format suivant:

Album 21 (12 chansons, 00:47:11)
01: White_Wedding - Billy_Idol - 00:04:12
02: Stand_And_Deliver - Adam_&_The_Ants - 00:03:33
03: You_Spin_Me_Around - Dead_Or_Alive - 00:03:14
04: Wired_For_Sound - Cliff_Richard - 00:03:38
05: Some_Like_It_Hot - The_Power_Station - 00:03:45
06: 99_Luftballons - Nena - 00:03:50
07: Keep_On_Loving_You - Reo_Speedwagon - 00:03:22
08: Seven_Into_The_Sea - In_Tua_Nua - 00:03:51
09: Love_Is_A_Battlefield - Pat_Benatar - 00:05:20
10: Etienne - Guesch_Patti - 00:04:07
11: This_Is_Not_A_Love_Song - Public_Image_Limited - 00:04:12
12: Love_Missile_F1-11 - Sigue_Sigue_Sputnik - 00:04:07

2.7   Tester la classe Album

Ajoutez au fichier test.py une série de tests pour tester la classe Album.

2.8   Le programme

Finalement, complétez votre programme par une série d'instructions qui:

  1. lit dans le fichier music-db.txt, ligne par ligne, des descriptifs de chanson au format décrit en tête de cette section;
  2. pour chaque ligne lue, construite une instance de Chanson;
  3. stocke ses chansons dans un album avec identifiant le numéro 1;
  4. lorsque le nombre de chansons stockés dans cet album a atteint 100 chansons ou la durée dépasserait 75 minutes, imprime à la console un descriptif de cet album avec les chansons accumulées, suivant l'exemple donné ci-dessus;
  5. poursuit la lecture du fichier et l'ajout des chansons dans un album suivant (incrémentez le numéro identifiant l'album de 1 pour chaque nouvel album);
  6. répète ces étapes jusqu'à ce que le fichier est vide et imprime le dernier album.

Si tout va bien votre programme final produira l'output suivant

Album 1 (17 chansons, 01:10:55)
01: Let's_Dance - David_Bowie - 00:04:05
02: Relax - Frankie_Goes_To_Hollywood - 00:03:54
03: Purple_Rain - Prince - 00:05:48
04: Enjoy_The_Silence - Depeche_Mode - 00:04:13
05: Chacun_Fait_C'Qui_Lui_Plait - Chagrin_D'amour - 00:04:08
06: Love_Missile_F1-11 - Sigue_Sigue_Sputnik - 00:04:06
07: Spaceman - Babylon_Zoo - 00:03:59
08: Hijo_De_La_Luna - Mecano - 00:04:19
09: 7_Seconds - Youssou_N'Dour_&_Neneh_Cherry - 00:03:48
10: Osez_Josephine - Alain_Bashung - 00:02:57
11: Dejeuner_En_Paix - Stephan_Eicher - 00:03:27
12: New_Gold_Dream - Simple_Minds - 00:05:31
13: Missing - Everything_But_The_Girl - 00:04:44
14: Nineteen - Paul_Hardcastle - 00:03:38
15: Killer - Adamski - 00:04:13
16: Unbelievable - EMF - 00:03:29
17: Overload - Sugababes - 00:04:36

Album 2 (17 chansons, 01:11:24)
01: Ice_Ice_Baby - Vanilla_Ice - 00:04:29
02: Do_You_Really_Want_To_Hurt_Me - Culture_Club - 00:04:23
03: Under_The_Milky_Way - The_Church - 00:04:57
04: Shout - Tears_For_Fears - 00:06:29
05: Pure_Morning - Placebo - 00:04:15
06: Porcelain - Moby - 00:04:00
07: Toi_Mon_Toit - Elli_Medeiros - 00:03:37
08: Just_A_Friend_Of_Mine - Vaya_Con_Dios - 00:03:22
09: Sleeping_Satellite - Tasmin_Archer - 00:04:36
10: I_Won't_Let_You_Down - DPH - 00:04:05
11: A_Girl_Like_You - The_Smithereens - 00:04:36
12: Ready_To_Go - Republica - 00:03:39
13: Oh_Carolina - Shaggy - 00:03:10
14: La_Sonora - Starflam - 00:03:49
15: Tombe_Pour_La_France - etienne_Daho - 00:04:13
16: The_Captain_Of_My_Heart - Double - 00:03:58
17: Human - Human_League - 00:03:46

...

Album 21 (12 chansons, 00:47:11)
01: White_Wedding - Billy_Idol - 00:04:12
02: Stand_And_Deliver - Adam_&_The_Ants - 00:03:33
03: You_Spin_Me_Around - Dead_Or_Alive - 00:03:14
04: Wired_For_Sound - Cliff_Richard - 00:03:38
05: Some_Like_It_Hot - The_Power_Station - 00:03:45
06: 99_Luftballons - Nena - 00:03:50
07: Keep_On_Loving_You - Reo_Speedwagon - 00:03:22
08: Seven_Into_The_Sea - In_Tua_Nua - 00:03:51
09: Love_Is_A_Battlefield - Pat_Benatar - 00:05:20
10: Etienne - Guesch_Patti - 00:04:07
11: This_Is_Not_A_Love_Song - Public_Image_Limited - 00:04:12
12: Love_Missile_F1-11 - Sigue_Sigue_Sputnik - 00:04:07

2.9   Tester le programme

Complétez le fichier test.py avec quelques tests pour démontrer que vos 3 classes Duree, Chanson et Album collaborent correctement et peuvent être utilisés pour créer des albums de chansons.

3   Diagramme de classes

Le diagramme de classes suivant résume les différentes classes et méthodes à implémenter lors de cette mission :

/syllabus/info1-exercises/assets/class_diagram_mission8.png

4   Remise de votre solution

Pour cette mission, vous devez soumettre votre programme mission8.py, le fichier test.py avec vos fonctions de tests pour les différentes classes que vous avez implémenté et votre fichier README.txt au serveur de soumissions de programmes du cours.

Votre fichier mission8.py doit contenir une définition des classes Duree, Chanson et Album, ainsi qu'une série d'instructions pour lire le fichier et créer et imprimer les albums.

Votre fichier test.py doit au moins contenir des tests pour les différentes méthodes des classes Duree, Chanson et Album, ainsi qu'une série d'instructions pour lancer tous les tests.

L'exécution de votre programme mission8.py doit imprimer l'output ci-dessus sur base du fichier original music-db.txt. Il ne vous est pas permis de faire des modifications à ce fichier.


        
        
Questions complémentaires

Questions complémentaires

1   SMS Store


        
        

2   Création d'objets depuis un fichier


        
        

3   Personne

Créer une classe Personne décrivant des personnes physiques ayant un nom (un string), un attribut booléen 'desire_enfant' et une liste d'enfants (d'autres instances de la même classe) et comme méthodes:

  • les méthodes magiques __init__ et __str__ ;
  • avoir_enfant_avec(autre) crée une nouvelle personne avec un nom inconnu (None), à condition que la personne même et l'autre personne désirent un enfant ;
  • une méthode auxiliaire ajoute_enfant(bebe) utilisée par avoir_enfant_avec(autre) pour ajouter un enfant à la liste des enfants de chacun des deux parents ;
  • renommer(nom) donne un nouveau nom à la personne ;
  • premier_ne() retourne le premier enfant de la personne.

Utilisez et testez cette classe pour créer une grande famille de personnes.

<string>

Table des matières

Mission 9 - Héritage

Mission 9 : Héritage

Mission 9 : Héritage

1   Introduction

Le traitement de données commerciales et financières est un des champs majeurs d'application de l'informatique. De nos jours, la moindre PME utilise l'informatique pour gérer sa comptabilité, ses commandes et sa facturation, et l'infrastructure informatique est devenue un élément critique de toute grande entreprise, dont la supervision représente un poste clé au sein de l'exécutif, celui de Chief Information Officer ou CIO.

Invoice Manager, un logiciel de facturation pour PME. (© Hillstone Software)

PCLine s.p.r.l., une société de vente de matériel et de service informatique locale de Louvain-la-Neuve, fait appel à vos services pour développer ses applications informatisées de facturation. Les gérants de PCLine disposent déjà d'un programme pour imprimer leurs factures et calculer la TVA et les totaux. Ils désirent développer également la livraison des articles et de pièces, en intégrant l'impression des bordereaux de livraison dans leur logiciel de facturation existant, sans devoir écrire complètement leur logiciel existant. Heureusement, leur logiciel étant écrit en Python dans un style orienté objets, leur consultant de l'UCLouvain leur a confirmé qu'il était possible de l'étendre sans le modifier au moyen des mécanismes d'héritage de Python. Ils ont donc confié aux étudiants de 1er Bac la tâche d'ébaucher la représentation des pièces en catalogue, leur intégration dans la facturation, ainsi que l'impression des bordereaux de livraison en plus de l'impression des factures.

2   Objectifs

A l'issue de cette mission, chacun d'entre vous :

  • pourra masquer les variables d'instance d'une classe et écrire des méthodes pour y accéder;

  • aura appris la notion de variable de classe et son utilité;

  • pourra expliquer en ses propre mots et illustrer par l'exemple les principes de l'héritage en Python:

    * l'héritage d'une classe;
    * la redéfinition de méthodes;
    * l'utilisation de ``self`` et ``super()``;
    
  • sera capable d'utiliser l'héritage pour étendre un programme Python;

  • pourra utiliser les méthodes magiques comme

    * ``__init__`` pour initialiser les objets d'une classe;
    * ``__str__`` pour retourner une représentation textuelle d'un instance d'une classe;
    * ``__eq__`` pour définir l'égalité entres objets d'une classe.
    

3   Préparation, étude et apprentissage

La matière relative à cette mission est décrite dans les sections suivantes de la partie Objects du syllabus en ligne:

ainsi que les annexes:

4   Questionnaire de démarrage

4.1   Questions à choix multiple

Les questions à choix multiples de cette mission sont accessibles en ligne depuis https://inginious.info.ucl.ac.be/course/LSINF1101-PYTHON/Session10_QCM


        
        

4.2   Questions ouvertes

4.2.1   Egalité

Considérez une classe Pair :

class Pair:

    def __init__(self, x, y):
        self.a = x
        self.b = y

    def __str__(self):
        return str(self.a) + ", " + str(self.b)

Maintenant considérez le code suivant :

p1 = Pair(9, 42)
p2 = Pair(9, 42);
print(p1 == p2)

La dernière instruction affichera False. (Pourquoi?)

Ajoutez une méthode __eq__(self, p) à la classe Pair qui compare la valeur de deux paires, de manière à ce que print(p1 == p2) imprimera True au lieu de False.

Dans l'implémentation de votre méthode pensez également à gérer le cas où p == None.


        
        

4.2.2   L'héritage

L'héritage est un principe de base de la programmation orientée objet. Considérons les classes A, B, C et D ci-dessous :

class A :

  def m1(self) :
      print("A 1")

  def m2(self) :
      print("A 2")

  def m3(self) :
      self.m1()   # appel à la méthode m1 sur la même instance

  def nom(self) :
      return "A"

class B(A) :

  def m2(self):
      print("B 2")

class C(A):

    def m1(self) :
        print("C 1")

    def nom(self):
        return "C"

class D(C) :

    def m2(self) :
        print("D 2")

Considérant ces quatre classes, on vous demande de :

  • Expliquez ce que représente le mot self dans la définition de ces différentes méthodes.
 
 
 
 

  • Dessiner un diagramme reprenant ces quatre classes.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

  • Expliquer ce qui sera affiché lors de l'exécution des instructions Python ci-dessous :
a = A()
print(a.nom())
a.m1()
a.m2()
a.m3()
b = B()
print(b.nom())
b.m1()
b.m2()
b.m3()
c = C()
print(c.nom())
c.m1()
c.m2()
c.m3()
d = D()
print(d.nom())
d.m1()
d.m2()
d.m3()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

4.2.3   C'est super !

  • Expliquez le rôle de la fonction spécial super() dans le langage Python. Donnez un exemple.
 
 
 
 
 

  • Considérons les classes E et F ci-dessous :
class E :

    def m(self) :
        print("E 1")

    def n(self) :
        print("E 2")

    def p(self) :
        self.n()   # appel à la méthode n sur la même instance

class F(E) :

   def q(self) :
       print("F 1")

   def n(self) :
       super().n() # appeler la méthode définie sur la classe mère
       print("F 2")

   def r(self) :
        self.m() # appel à la méthode m sur la même instance

Expliquer ce qui sera affiché lors de l'exécution des instructions Python suivantes :

f = F()
f.q()
f.m()
f.r()
f.n()
f.p()
 
 
 
 
 
 
 

4.2.4   Rectangle

Considérons la classe Figure reprise ci-dessous :

class Figure:

    def __init__(self,x,y,visible=False) :
        """
        @pre x, y sont des entiers représentant des positions sur l'écran
        @post Une figure a été créée avec centre de gravité aux coordonnées x,y.
              Cette figure n'est initialement pas visible.
        """
        self.x = x
        self.y = y
        self.__visible = visible

    def est_visible(self) :
        """
        @pre -
        @post a retourné la visibilité de cette figure
        """
        return self.__visible

    def surface(self) :
        """
        @pre -
        @post la surface (un float) de la figure a été calculé et retournée
        """
        pass            # code non fourni

Cette classe Figure est la classe mère d'un ensemble de classes permettant de représenter des figures géométriques. Chaque figure géométrique est placée à une position (x,y) (centre de gravité) sur l'écran et la classe contient des variables d'instance et des méthodes permettant de manipuler cette figure géométrique (notamment des méthodes permettant d'afficher la figure à l'écran, mais ces méthodes ne sont pas reprises dans les extraits présentés dans cet exercice). Parmi ces figures géométriques, on trouve notamment la classe Rectangle qui hérite de la classe Figure et dont un fragment est repris ci-dessous :

class Rectangle(Figure):

    def __init__(self,longueur,largeur,x,y) :
        """
        @pre longueur et largeur sont des entiers positifs
             x, y sont des entiers représentant des positions sur l'écran
        @post un rectangle dont le centre de gravite est en x,y
              et ayant comme longueur lo et comme largeur la a été créé
        """
        super().__init__(x,y)
        self.longueur = longueur
        self.largeur = largeur

    def __str__(self) :
        return str((self.longueur,self.largeur,self.x,self.y,self.est_visible()))

>>> r = Rectangle(10,20,0,0)
>>> print(r)
(10, 20, 0, 0, False)

Maintenant expliquez :

  • Quelles sont les variables d'instance qu'une instance de la classe Rectangle peut utiliser ?
  • Que se passe-t il lorsqu'une instance r de la classe Rectangle est créé?
  • Que fait l'appel à super() dans la méthode __init__ de la classe Rectangle ?
  • Que se passe-t il si on met cet appel à super() comme dernière instruction dans la méthode __init__ de la classe Rectangle ?
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Dans la classe Rectangle, faut-il redéfinir les méthodes suivantes (si oui, écrivez le code de la nouvelle méthode - si non, expliquez pourquoi ):

  • surface()
 
 
 
 
 
 
 
 

  • est_visible()
 
 
 
 

4.2.5   Variables privés


        
        

4.2.6   Carré

Comment feriez-vous maintenant pour définir une classe Carre qui étend la classe Rectangle et permet de représenter un carré ?

  • Ecrivez la méthode d'initialisation de la classe Carre (un carré se construit en indiquant les coordonnées de son centre de gravité et la longueur de son côté)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

  • Quelles sont les méthodes que vous devez redéfinir dans la classe "Carre" ?
 
 
 
 

  • Soient deux classes Circle et Ellipse. Quelles relations peut-on envisager entre ces deux classes ?
 
 
 
 

  • Ecrivez une méthode perimetre() de la classe Rectangle qui retourne le périmètre du rectangle.
 
 
 
 

  • Que faudrait-il faire pour avoir une méthode perimetre de la classe Carre?
 
 
 
 

4.2.7   Similitude

Définissez une méthode __eq__ pour la classe Figure, telle que deux figures sont égales si leur surface est égale.

 
 
 
 

Que se passe-t il si on veut comparer deux rectangles ayant la même surface? Par exemple:

>>> r1 = Rectangle(10,40,0,0)
>>> r2 = Rectangle(2,200,0,0)
>>> r1 == r2
 
 
 
 

Que se passe-t il si on veut comparer un rectangle avec un carré ayant la même surface? Par exemple:

>>> r = Rectangle(10,40,0,0)
>>> c = Carre(20,0,0)
>>> print(r == c)
 
 
 
 

4.2.8   Variable de classe

Et voici finalement une dernière question pour illustrer l'utilisation d'une variable de classe.

Complétez la classe Ticket ci-dessous:

"""
Un ticket de parking
"""
class Ticket :

    __prochain_numero = 1  # variable de classe pour générer le numéro du ticket

    def __init__(self) :
        """
        @pre  -
        @post Crée un ticket avec un nouveau numéro.
              Les numéros sont attribués séquentiellement à partir de 1.
        """
            # A COMPLETER

    def numero(self):
        """
        @pre  -
        @post retourne le numero de billet
        """
        return self.__numero


        
        

Mission 9 : Héritage

Mission 9 : Héritage

1   Description

Pour cette mission, vous disposez au départ d'un programme simple mission9.py permettant d'imprimer des factures. Ce programme comporte principalement deux classes:

  1. l'une représente un Article, c'est-à-dire une ligne dans la facture (correspondant à l'achat d'un article comme un laptop, ou les frais pour une service comme l'installation d'un réseau wifi);
  2. l'autre représente une Facture sous forme d'une liste d'articles (ou de services) et offre des méthodes permettant de l'imprimer.

Un fichier de test initiale test.py est également fournie. Exécuter ce fichier test produira l'exemple de facture suivant:

Facture PC Store - 22 novembre
===================================================================================
| Description                              |  prix HTVA |        TVA |  prix TVAC |
===================================================================================
| laptop 15" 8GB RAM                       |     743.79 |     156.20 |     899.99 |
| installation windows                     |      66.11 |      13.88 |      79.99 |
| installation wifi                        |      45.22 |       9.50 |      54.72 |
| carte graphique                          |     119.49 |      25.09 |     144.58 |
===================================================================================
| T O T A L                                |     974.61 |     204.67 |    1179.28 |
===================================================================================

Partant de ce code déjà fonctionnel, l'objectif principal de cette mission est de développer des classes qui héritent de la classe Article , en offrant des fonctionnalités supplémentaires tout en restant utilisables par la classe Facture . Dans un deuxième temps, vous ajouterez aussi une méthode à la classe Facture qui exploite ces nouvelles fonctionnalités.

Votre programme final devrait être capable de calculer et générer des factures plus complets comme

Facture No 1 : Facture PC Store - 22 novembre
===================================================================================
| Description                              |  prix HTVA |        TVA |  prix TVAC |
===================================================================================
| laptop 15" 8GB RAM                       |     743.79 |     156.20 |     899.99 |
| installation windows                     |      66.11 |      13.88 |      79.99 |
| installation wifi                        |      45.22 |       9.50 |      54.72 |
| carte graphique                          |     119.49 |      25.09 |     144.58 |
| Réparation (0.75 heures)                 |      46.25 |       9.71 |      55.96 |
| 1 * disque dur 350 GB @ 49.99            |      49.99 |      10.50 |      60.49 |
| 3 * souris bluetooth @ 15.99             |      47.97 |      10.07 |      58.04 |
| 5 * adaptateur DVI - VGA @ 12.00         |      60.00 |      12.60 |      72.60 |
| 2 * Java in a Nutshell @ 24.00           |      48.00 |       2.88 |      50.88 |
| 5 * souris bluetooth @ 15.99             |      79.95 |      16.79 |      96.74 |
===================================================================================
| T O T A L                                |    1306.77 |     267.22 |    1573.99 |
===================================================================================

et des bordereaux de livraison tels que celui-ci

Livraison - Facture No 1 : PC Store - 22 novembre
===================================================================================
| Description                              |  poids/pce |     nombre |      poids |
===================================================================================
| disque dur 350 GB @ 49.99 (!)            |    0.355kg |          1 |    0.355kg |
| souris bluetooth @ 15.99                 |    0.176kg |          3 |    0.528kg |
| adaptateur DVI - VGA @ 12.00             |    0.000kg |          5 |    0.000kg |
| Java in a Nutshell @ 24.00               |    0.321kg |          2 |    0.642kg |
| souris bluetooth @ 15.99                 |    0.176kg |          5 |    0.880kg |
===================================================================================
| 5 articles                               |            |         16 |    2.405kg |
===================================================================================
 (!) *** livraison fragile ***

2   Etapes

Voici les étapes à suivre.

2.1   Fichiers

Chargez les fichiers mission9.py et test.py et étudiez leurs contenus. Vous disposez des classes et fonctions suivants:

  • Article : cette classe représente un article de la facture. Elle contient une description et un prix et offre des méthodes permettant d'obtenir ces données et de calculer le prix de l'article avec TVA. Analysez attentivement le code de cette classe. Remarquez comment les différentes méthodes font appel à la méthode prix() . Ceci est important quand on hérite de cette classe: en redéfinissant la méthode prix() on modifiera aussi indirectement les autres méthodes qui y font appel.
  • Facture : cette classe représente une facture. Elle contient une liste d'articles. Elle offre principalement une méthode __str__ qui retourne un string détaillé représentant la facture, qui peut être imprimé avec la méthode print(), ainsi que plusieurs méthodes auxiliaires utilisées par cette méthode __str__.
  • test_articles(l) : une fonction de test de la classe Article qui imprime une liste d'articles l.
  • test_facture(f) : une fonction de test de la classe Facture qui produit l'impression d'une facture reprise dans le premier exemple ci-dessus.

Vous devrez vous-mêmes créer au moins deux classes ArticleReparation et ArticlePiece qui héritent de la classe Article, une classe Piece (utilisée par la classe ArticlePiece), ainsi que deux méthodes supplémentaires dans Facture , selon les instructions qui suivent.

2.2   La classe ArticleReparation

  • Au fichier mission9.py , ajoutez une nouvelle classe ArticleReparation qui hérite de la classe Article . Cette nouvelle classe représente une prestation de réparation de durée donnée (un float, en heures).

  • Définissez une méthode d'initialisation avec la durée en paramètre.

  • Re-définissez la méthode description() pour fournir un descriptif adéquat comme Reparation (0.75 heures).

  • Re-définissez la méthode prix() pour calculer un coût fixe de 20 euro plus un coût variable de 35 euro/h. Pour une réparation de 0.75 heures ça donne donc un coût de 20 + 35*0.75 = 46.25 euro HTVA.

  • Dans le fichier test.py , ajoutez des tests pour tester cette nouvelle classe et son utilisation dans une facture. Par exemple, vérifiez que la ligne correspondant à une réparation soit affiché comme:

    Facture PC Store - 22 novembre
    ===================================================================================
    | Description                              |  prix HTVA |        TVA |  prix TVAC |
    ===================================================================================
    | ...                                                                             |
    | Réparation (0.75 heures)                 |      46.25 |       9.71 |      55.96 |
    ===================================================================================
    | T O T A L                                |    1020.86 |     214.38 |    1235.24 |
    ===================================================================================
    

2.3   Les classes ArticlePiece et Piece

Créez une nouvelle classe ArticlePiece qui hérite de Article et qui représente l'achat pas d'un seul article mais d'un nombre donné d'une pièce donnée. (Par exemple, 3 souris Bluetooth à 15.99 EUR par pièce.)

Implémentez d'abord une nouvelle classe Piece qui représente la pièce dont on veut facturer plusieurs exemplaires. Elle comporte les données suivantes:

- une description (string), p.ex. 'souris bluetooth';
- un prix unitaire (float), p.ex. 15.99 Euro;

et, optionnellement

- un poids unitaire en kg (float), p.ex. 0,154 kg;
- un indicateur booléen indiquant si la pièce est fragile, p.ex. un disque dur est fragile mais pas une souris;
- un indicateur booléen indiquant si la pièce est à taux de TVA réduit, p.ex. les livres bénéficient de TVA réduite.
  • Ajoutez une méthode d'initialisation permettant d'initialiser toutes ces données. Cette méthode d'initialisation doit aussi être utilisable avec seulement les deux paramètres obligatoires (description et prix) pour les pièces de poids négligeable, non fragiles et à taux de TVA normal (en assignant des valeurs par défaut pour les autres paramètres dans ce cas).
  • Ajoutez des méthodes accèsseurs (description() , prix() , poids() , fragile() , tva_reduit()) pour toutes ces données.
  • Ajoutez une méthode magique __eq__ afin que deux pièces sont considérées égales ( == ) si elles ont la même description et le même prix (les autres données sont ignorées pour la comparaison).

Ensuite implémentez la classe ArticlePiece qui hérite de Article

  • Ajoutez une méthode d'initialisation prenant le nombre et la pièce en paramètres.
  • Ajoutez des méthodes accèsseurs pour ces deux attributs.
  • Re-définissez la méthode description() pour fournir un texte reprenant la description de la pièce, le nombre souhaité de cette pièce et son prix unitaire, par exemple: 3 * souris bluetooth @ 15.99 .
  • Re-définissez la méthode prix() pour faire le produit du prix unitaire de la pièce par le nombre de pièces souhaité.
  • Re-définissez la méthode taux_tva() pour appliquer un taux de 6% aux pièces à taux de TVA réduit, tout en gardant le taux de TVA original pour d'autres pièces.

Finalement, dans le fichier test.py , ajoutez des tests pour tester ces nouvelles classes et leur utilisation dans une facture. Par exemple, vérifiez que les lignes correspondant aux articles pièces soient affichés comme:

Facture PC Store - 22 novembre
===================================================================================
| Description                              |  prix HTVA |        TVA |  prix TVAC |
===================================================================================
| ...                                                                             |
| 3 * souris bluetooth @ 15.99             |      47.97 |      10.07 |      58.04 |
| 2 * Java in a Nutshell @ 24.00           |      48.00 |       2.88 |      50.88 |
| ...                                                                             |
===================================================================================
| T O T A L                                |    1306.77 |     267.22 |    1573.99 |
===================================================================================

2.4   Numérotation des factures

Modifiez la classe Facture pour que chaque nouvelle facture reçoive un numéro séquentiel unique, qui apparait dans l'en-tête de la facture.

2.5   Compter le nombre de pièces

Dans la classe Facture, ajoutez une méthode def nombre(self,pce) qui retourne le nombre d'exemplaires d'une Piece pce dans la facture, en totalisant sur tous les articles qui concernent cette pièce. (Vous pouvez utiliser le fait que le comparateur ``==`` a été redéfinie dans la classe ``Piece`` (via la méthode magique ``__eq__`` que vous avez ajoutée).)

2.6   Bordereau de livraison

Dans la classe Facture, ajoutez une méthode print_livraison() qui imprime un bordereau de livraison comme

Livraison - Facture No 1 : PC store 22 octobre
===================================================================================
| Description                              |  poids/pce |     nombre |      poids |
===================================================================================
| disque dur 350 GB (!)                    |    0.355kg |          1 |    0.355kg |
| souris bluetooth                         |    0.176kg |          3 |    0.528kg |
| adaptateur DVI - VGA                     |    0.000kg |          5 |    0.000kg |
| Java in a Nutshell                       |    0.321kg |          2 |    0.642kg |
| souris bluetooth                         |    0.176kg |          5 |    0.880kg |
===================================================================================
| 5 articles                               |            |         16 |    2.405kg |
===================================================================================
 (!) *** livraison fragile ***

Ce bordereau:

  • imprime une en-tête avec la description de la facture;
  • imprime toutes les pièces dans la facture avec, pour chacune, sa description, son poids unitaire, le nombre facturé et le poids correspondant;
  • ajoute une marque (!) dans la description des pièces fragiles;
  • totalise et imprime à la fin le nombre d'articles, le nombre de pièces et le poids total;
  • imprime un message supplémentaire (!) *** livraison fragile *** si (et seulement si) la livraison contient une ou plusieurs pièces fragiles.

Remarquez que les détails imprimés dans ce bordereau de livraison ne concernent que les articles de type ArticlePiece; les autres articles sont ignorés. Pour faciliter le formatage du texte, vous pouvez utiliser la méthode format, déjà utilisée à plusieurs endroits dans la classe Facture. Si vous ne la connaissez pas, n'hésitez pas à chercher en-ligne comment cette méthode format fonctionne exactement. Pour implémenter la méthode print_livraison() , réutiliser un maximum de méthodes déjà existantes de la classe Facture .

Finalement, modifiez le fichier test.py pour tester votre nouvelle méthode. En particulier, vérifiez qu'un bordereau de livraison soit affiché comme:

Livraison - Facture No 1 : PC Store - 22 novembre
===================================================================================
| Description                              |  poids/pce |     nombre |      poids |
===================================================================================
| disque dur 350 GB @ 49.99 (!)            |    0.355kg |          1 |    0.355kg |
| souris bluetooth @ 15.99                 |    0.176kg |          3 |    0.528kg |
| adaptateur DVI - VGA @ 12.00             |    0.000kg |          5 |    0.000kg |
| Java in a Nutshell @ 24.00               |    0.321kg |          2 |    0.642kg |
| souris bluetooth @ 15.99                 |    0.176kg |          5 |    0.880kg |
===================================================================================
| 5 articles                               |            |         16 |    2.405kg |
===================================================================================
 (!) *** livraison fragile ***

3   Diagramme de classes

Le diagramme de classes suivant résume les différentes classes et méthodes à implémenter lors de cette mission :

/syllabus/info1-exercises/assets/class_diagram_mission9.png

4   Remise de votre solution

Pour cette mission, vous devez soumettre toutes les classes de votre programme dans un seul fichier mission9.py, vos classes tests dans un fichier test.py, ainsi que votre fichier README.txt qui décrit comment on peut tester votre code.

Votre fichier mission9.py doit contenir les classes Facture, Article, ArticleReparation, ArticlePiece et Piece.

Votre fichier test.py doit contenir des tests pour chacune des classes et étappes de cette mission, ainsi qu'une série d'instructions à la fin pour lancer tous les tests automatiquement lors de l'exécution du fichier.

L'exécution de votre programme mission9.py doit imprimer une facture et un bon de livraison comme illustré plus haut dans ce document.


        
        

5   Challenge

Il est possible d'ajouter de multiples variantes d'article à ce programme. Par exemple:

  • étendre ArticlePiece en ArticlePieceGros qui applique une dégression sur les prix en fonction du nombre commandé;
  • ajouter une extension d'Article qui fait référence à une configuration de PC et calcule le prix correspondant (taille mémoire, CPU, écran, capacité disque, etc);
  • étendre ArticleReparation en ArticleReparationUrgente avec des tarifs plus élevés;
  • ajouter une extension d'Article pour des frais de déplacement;
  • ...

On peut également ajouter des calculs supplémentaires sur les factures, par exemple un bilan des frais de main d'oeuvre. Un peu plus difficile, modifier la méthode printLivraison() de la classe Facture pour n'imprimer qu'une seule ligne par pièce qui cumule les articles correspondants, comme dans la méthode nombre() .

Questions complémentaires

Questions complémentaires

1   Variables d'instance

Quelqu'un a programmé une classe Compte représentant un compte bancaire avec 2 attributs privés __titulaire (représentant le titulaire du compte) et __solde (représentant le montant sur le compte, initialement zéro) et 1 attribut publique représentant la banque du compte.

class Compte :

    def __init__(self, banque, titulaire, solde = 0) :
        self.banque = banque
        self.__titulaire = titulaire
        self.__solde = solde

    def banque(self) :
        return self.banque

    def titulaire(self):
        return self.__titulaire

    def solde(self):
        return self.__solde

    def __str__(self) :
        return "Banque: " + self.banque() \
           + " Compte: " + self.titulaire() \
           + " Solde: " + str(self.solde())

a = Compte("ShittyBank","Kim")
print(a)

Malheureusement, quand on exécute l'instruction print(a), une erreur se produit:

Traceback (most recent call last):
  > print(a)
  > print(self.banque())
  > TypeError: 'str' object is not callable

Quel est le problème? Pouvez-vous corriger le code?

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

2   Variable de classe


        
        

<string>

Table des matières

Mission 10 - Polymorphisme

Mission 10

Mission 10

1   Introduction

1.1   Objectifs

Dans cette mission, vous allez approfondir votre compréhension de concepts importants de la programmation orientée objets déjà abordés dans les deux missions précédentes, ainsi que quelques nouveaux concepts :

  • les classes, objets, variables et méthodes d'instance ;
  • les variables et méthodes de classe ;
  • les variables et méthodes privés, les méthodes accesseurs et mutateurs ;
  • la portée des variables d'instance ;
  • l'héritage, la redéfinition et l'écrasement de méthodes, le polymorphisme ;
  • la liaison dynamique et les subtilités de la sémantique de self et super().

Vous apprendrez également à écrire des tests unitaires pour vos programmes orientés objets.

1.2   Préparation, étude et apprentissage

Si vous n'avez pas encore eu le temps de relire en détail les différents chapitres de la partie Objects du syllabus en ligne, maintenant est venu le moment de rattraper votre retard. Le syllabus explique bien différents concepts, sur un autre exemple que les exemples utilisés dans le cours magistral :

On vous conseille également de tester et de jouer avec les différents exemples de code qui se trouvent dans les annexes suivantes, venant soit du syllabus en ligne soit correspondant aux exemples du cours magistral :

Dans cette mission, vous devrez également utiliser le framework unittest pour produire des classes de test. En préparation de cette mission, consultez donc la documentation de ce cadre de test, et essayez de faire quelques classes test simple en utilisant cet approche. Un bon tutoriel couvrant, entre autres, les tests unitaires avec unittest se trouve ici .

2   Questionnaire de démarrage

2.1   Questions à choix multiple

Les questions à choix multiples de cette mission sont accessibles en ligne depuis https://inginious.info.ucl.ac.be/course/LSINF1101-PYTHON/Session10_2019_QCM


        
        

2.2   Questions ouvertes

2.2.1   Vocabulaire

On vous donne le code suivant qui teste certaines fonctionnalités du module random.

import unittest
import random

class RandomTest(unittest.TestCase):
    """Classe de tests utilisée pour tester les fonctions du module 'random'"""

    def setUp(self):
        """Initialisation des tests."""
        self.l = list(range(10))

    def test_choice(self):
        """Test de fonctionnement de la fonction random.choice"""
        e = random.choice(self.l)
        # Vérifie que 'e' est dans 'l'
        self.assertIn(e,self.l)

    def test_shuffle(self):
        """Test le fonctionnement de la fonction random.shuffle"""
        random.shuffle(self.l)
        self.l.sort()
        self.assertEqual(self.l, list(range(10)))

    def test_sample(self):
        """Test le fonctionnement de la fonction random.sample"""
        extrait = random.sample(self.l, 5)
        for element in extrait:
            self.assertIn(element,self.l)
        self.assertRaises(ValueError, random.sample, self.l, 20)

# Pour lancer automatique ces tests quand on exécute ce fichier
if __name__ == '__main__':
    unittest.main()

Considérant cette classe, on vous demande de :

  • Expliquez cet extrait de code

    if __name__ == '__main__':
        unittest.main()
    
 
 
 
 

  • Expliquez le rôle de import unittest et pourquoi c'est indispensable.
 
 
 
 

  • Expliquez cette ligne class RandomTest(unittest.TestCase): et pourquoi c'est indispensable.
 
 
 
 

  1. def setUp(self)
 
 
 
 

  1. self.assertEqual()
 
 
 
 

  1. self.assertIn()
 
 
 
 

  1. self.assertRaises()
 
 
 
 

2.2.2   Tests unitaires

Implémentez une classe de tests unitaires MyClassTest qui hérite de unittest.TestCase qui teste la fonction carre_parfait du module totest. (En mathématiques, un carré parfait est le carré d'un entier.)

Soit la fonction carre_parfait du module totest ayant pour spécifications :

def carre_parfait (x) :
    '''
    retourne true si l'entier en argument est un carré parfait, false sinon
    '''
# CODE NON FOURNI

Complétez la classe de test ci-dessous :

import totest
import unittest

class MyClassTest(unittest.TestCase) :

    # todo

if __name__ == '__main__':
    unittest.main()
  • Ecrivez au moins trois tests unitaires pour vérifier l'implémentation de cette fonction
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

  • Que donnent-vos tests unitaires pour les implémentations suivantes :

    1. def carre_parfait (x) :
         return True
      
    2. def carre_parfait (x) :
          return False
      
    3. def carre_parfait (x) :
          cur = 0
          while not cur*cur == x :
              cur += 1
          return True
      
    4. import math
      def carre_parfait (x) :
          root = math.sqrt(x)
          return root.is_integer()
      
    5. import math
      def carre_parfait (x) :
          if x < 0 : return False
          root = math.sqrt(x)
          return root.is_integer()
      

2.2.3   Centre d'expédition d'Amazon


        
        

Mission 10

Mission 10

1   Description

L'objectif de cette mission est de créer des robots virtuels maintenant un état représentant leur position à l'écran et des opérations permettant de les faire bouger sur l'écran. On peut se baser sur plusieurs bibliothèques graphiques pour implémenter de tels robots. Cette mission vise à illustrer que, grace au polymorphisme, il devient relativement facile de remplacer une telle bibliothèque par une autre sans devoir modifier beaucoup de code.

On vous fournira une première implémentation basé sur la bibliothèque graphics.py de Python. A vous de proposer une implémentation alternative en utilisant la bibliothèque turtle. Ces deux types de robots sont polymorphe: ils comprennent exactement les mêmes messages, mais l'un est implémenté avec des positions absolues sur un plan XY, tandis que l'autre utilise des positions relatives.

Ensuite on vous demandera d'étendre davantage la fonctionnalité de ces robots, ce qui vous permettra de découvrir la puissance du concept de l'héritage pour la réutilisation du code.

Il sera aussi important de bien tester à la fois les classes qui vous sont fournies et que vous implémenterez, avec des tests unitaires. C'est-à-dire que vous créerez, par classe à tester, une classe test correspondante, avec des méthodes tests pour chacune des méthodes de la classe à tester. Ceci vous permet de tester, à une granularité fine, les différents unités (les classes et les méthodes) de votre code orienté objet.

Les différents concepts traités dans cette mission seront, entre autres : le polymorphisme, la composition, la délégation, l'héritage, la duplication et la réutilisation de code, la substitutabilité, l'utilisation de self et de super(), et les tests unitaires. Vous travaillerez par groupes de deux.

2   Etapes

2.1   Avant de commencer...

Avant de commencer, installez le package graphics.py permettant de dessiner des figures simples dans une fenêtre graphique. Ce package sera utilisée par la classe XYRobot. Vous pouvez installer ce package facilement depuis Thonny en suivant les étapes suivantes: (1) Sélectionner le menu Tools > Manage Packages... en Thonny; (2) taper graphics.py dans le champs de recherche pour retrouver le bon package et appuyez sur Install . (On a besoin du package graphics.py développé par John Zelles pour utilisation avec son livre Python Programming: An Introduction to Computer Science. La documentation pour ce package se trouve ici .)

2.2   La classe XYRobot

La classe XYRobot vous est fournie dans le fichier XYRobot.py sur le site inginious où vous pouvez remettre votre solution. Analysez le code de cette classe attentivement. Elle :

  • Utilise le package graphics.py que vous avez installé dans l'étape prédédente.

  • Utilise des fonctions goniométriques comme cos et sin ainsi que la constante mathématique pi, fournies par le module math.

  • Représente un robot virtuel ayant un nom, une position (x, y), et une direction (angle). Quand il bouge, ce robot dessine ses mouvements dans une fenêtre représentant un plan XY.

  • En plus des méthodes habituelles __init__ et __str__ ainsi que des méthodes accesseurs et mutateurs, cette classe implémente des méthodes comme:

    • move_forward(distance) : fait avancer le robot de distance pixels et trace une ligne lors de ce mouvement
    • move_backward(distance) : fait reculer le robot de distance pixels et trace une ligne lors de ce mouvement
    • turn_left() : fait tourner le robot de 90 degrés vers la gauche (dans le sens contraire des aiguilles d'une montre)
    • turn_right() : fait tourner le robot de 90 degrés vers la droite (dans le sens des aiguilles d'une montre)

Appeler ces méthodes fait bouger le robot et dessine des figures sur un plan XY. Il suffit d'exécuter le code fourni dans le fichier pour avoir un exemple concret. N'oubliez pas d'installer la bibliothèque graphics.py avant d'exécuter ce fichier.

2.3   Tester la classe XYRobot

Tandis que l'implémentation de la classe XYRobot vous est fournie, il manque une classe avec des tests unitaires afin de vérifier que le robot bouge et met à jour ses attributs correctement. L'objectif de cette étape sera donc de créer une classe test avec des tests unitaires pour la classe qui vous est fournie.

Implémentez cette classe de test TestXYRobot afin de vérifier le comportement correct des différentes méthodes de la classe XYRobot. Pour réaliser vos tests, il est important à savoir que le package ``graphics.py`` considère que le point avec position (x=0,y=0) se trouve dans le coin supérieur gauche de la fenêtre.

Position de l'origine et orientation du plan XY pour la bibilothèque ``graphics``

Par exemple, quand on crée un nouveau robot r2d2 = XYRobot("R2-D2") il se trouvera à la position (x=0,y=0) avec comme angle 0 (direction Est). Après avoir exécuté r2d2.move_forward(50) le robot devrait se trouver à la position (x=50, y=0), approximativement, à cause des arrondis dans les calculs. Ensuite, après avoir exécuté r2d2.turn_right() l'angle du robot sera 90° (approximativement), etc.

Soyez le plus complet possible dans vos tests. Mettez votre classe test TestXYRobot dans un fichier séparé TestXYRobot.py qui s'occupera de charger le fichier XYRobot.py et d'exécuter les différents tests sur la classe XYRobot.

2.4   La classe TurtleBot

Maintenant c'est à vous d'implémenter une classe TurtleBot qui est polymorphe avec la clase XYRobot de l'étape précédente. C'est-à-dire que, en plus des méthodes __init__ et __str__ et des méthodes accesseurs (dont angle() et position()) et mutateurs, elle doit implémenter les mêmes méthodes :

  • move_forward(distance) : fait avancer le robot de distance pixels et trace une ligne lors de ce mouvement
  • move_backward(distance) : fait reculer le robot de distance pixels et trace une ligne lors de ce mouvement
  • turn_left() : fait tourner le robot de 90 degrés vers la gauche (dans le sens contraire des aiguilles d'une montre)
  • turn_right() : fait tourner le robot de 90 degrés vers la droite (dans le sens des aiguilles d'une montre)

La différence majeure est que la classe TurtleBot fait ces dessins via un objet de type Turtle. Cette classe sera donc assez facile à implémenter en utilisant un objet de type Turtle comme attribut. Le travail d'avancer, tourner et dessiner pourra alors être délégué à cette tortue. Pour rappel, la classe Turtle du package turtle.py fournit des méthodes comme position, heading, forward, backward, right et left. (Voici la documentation pour ce package.)

Pour implémenter la classe ``TurtleBot`` et effectuer vos tests, il est important à savoir que dans la fenêtre graphique du turtle, la position (x=0,y=0) se trouve au milieu de la fenêtre, l'axe X pointe vers la droite et l'axe Y vers le haut.

Position de l'origine et orientation du plan XY pour la bibilothèque ``turtle``

2.5   Tester la classe TurtleBot

Pour tester le comportement correct de la classe TurtleBot, on vous fournit un fichier TestTurtleBot.py (ce fichier se trouve sur le site inginious où vous pouvez remettre votre solution.) Ce fichier test contient des tests unitaires pour votre classe TurtleBot qui doit se trouver dans un fichier TurtleBot.py.

Vous pouvez aussi vérifier que le comportement de votre robot est correct en vérifiant que ce qu'il dessine sur l'écran correspond à ce que vous attendez.

2.6   Etendre les classes XYRobot et TurtleBot

Maintenant, on veut étendre la fonctionnalité des robots. A vos deux classes XYRobot et TurtleBot , ajoutez des méthodes pour:

  • garder une trace des actions exécutées auparavant par ce robot;
  • rejouer ces actions à l'envers (c'est-à-dire de défaire ces actions).

Plus spécifiquement, il faut ajouter les deux méthodes suivantes:

  • history() : retourne l'historique des actions précédentes, comme une liste du style: [('forward', 50), ('left', 90), ('forward', 50), ...]
  • unplay() : rejouer les actions précédentes dans le sens inverse et vider l'historique après avoir rejoué ces actions.

Même si faire du copier-coller de code entre ces deux classes est encore permis pour cette exercice, dans l'étapes suivantes on utilisera l'héritage pour éviter ce copier-coller en ajoutant une classe mère avec le code commun entre ces deux classes.

2.7   Tester les classes XYRobot et TurtleBot

Ajouter aux deux classes de test TestXYRobot et TestTurtleBot les tests unitaires nécessaires pour tester si les deux classes XYRobot et TurtleBot, avec la fonctionnalité historique et la fonctionnalité pour défaire les actions, marchent correctement.

2.8   Restructurer les classes XYRobot et TurtleBot

Si vous n'avez pas encore utilisé l'héritage lors de l'étape précédente, il est fort probable que vous ayez créé des méthodes très similaires dans les deux classes XYRobot et TurtleBot. Ces deux classes représentent tous les deux un robot ayant une mémoire contenant les actions déjà effectuées ainsi qu'une méthode pour défaire ces actions. Une bonne manière d'éviter le code redondant (recopié/dupliqué dans les deux classes) est de le mettre dans un classe mère Robot commune à ces deux classes, et de déclarer XYRobot et TurtleBot comme des classes filles de cette classe. En particulier, la classe mère peut contenir tout le code pour retenir les actions effectuées et de les refaire dans le sens inverse.

Lors de cet étape on vous demande donc de :

  • Créer une nouvelle classe mère Robot qui doit se trouver dans un fichier Robot.py.
  • Réécrivez les classes XYRobot et TurtleBot comme sous-classes de Robot.
  • Bouger le code qui est commun entre les classes filles XYRobot et TurtleBot vers la classe mère Robot.

2.9   Retester les classes XYRobot et TurtleBot

Rejouez les tests unitaires TestXYRobot et TestTurtleBot de l'étape précédente sur la nouvelle version des classes XYRobot et TurtleBot qui héritent de leur nouvelle clases mère. Si tout va bien ces tests doivent toujours fonctionner. Si ce n'est pas le cas, adapter le code ou les tests où nécessaire.

3   Diagramme de classes

Le diagramme de classes suivant résume les différentes classes et méthodes à implémenter lors de cette mission :

/syllabus/info1-exercises/assets/class_diagram_mission10.png

4   Remise de votre solution

  1. Un fichier Robot.py qui contient la classe mère Robot avec le code de gestion de l'historique.

    (Si vous n'êtes pas arrivé à cette étape, remettez simplement un fichier vide ici.)

  2. Un fichier XYRobot.py qui contient la classe XYRobot qui hérite de Robot.

    (Si vous n'êtes pas arrivé à l'étape avec l'héritage de la classe Robot, remettez la version de votre classe XYRobot sans héritage ici.)

  3. Un fichier TurtleBot.py qui contient la classe TurtleBot qui hérite de Robot.

    (Si vous n'êtes pas arrivé à l'étape avec l'héritage de la classe Robot, remettez la version de votre classe TurtleBot sans héritage ici.)

  4. Un fichier TestXYRobot.py qui contient les tests unitaires pour votre classe XYRobot.

    Ce fichier TestXYRobot.py doit charger le fichier XYRobot.py et exécuter les différents tests unitaires sur la classe XYRobot.

  5. Un fichier TestTurtleBot.py qui contient les tests unitaires pour votre classe TurtleBot.

    Ce fichier TestTurtleBot.py doit charger le fichier TurtleBot.py et exécuter les différents tests unitaires sur la classe TurtleBot.


        
        
Questions complémentaires

Questions complémentaires

Héritage


        
        
<string>

Table des matières

Mission 11 - Listes chainées

Mission 11 : Les listes chaînées

Mission 11 : Les listes chaînées

/syllabus/info1-exercises/assets/linkedtrain.jpg

1   Introduction

Le Service des sports fait appel à vous dans le cadre du développement d'un système informatique pour la gestion des résultats de la course des 24h Vélo de Louvain-la-Neuve. Vous devez réaliser un programme Python permettant d'encoder et de manipuler les différentes données nécessaires (coureurs, résultats, classements) pour tenir à jour les classements en cours de course. Par exemple, il faut pouvoir afficher en temps réel, sur des écrans disposés dans la ville et sur internet, le classement des meilleurs temps pour le tour du circuit.

Un classement par temps (Tour de France 2013)

Pour cette mission, vous allez devoir implémenter une classe Python permettant de manipuler un tel classement et de le mettre à jour avec de nouveaux résultats. Le classement doit être ordonné, et on ne désire pas refaire le tri pour chaque nouveau résultat: il faut donc une structure de liste ordonnée avec des opérations qui maintiennent cet ordre. Vous utiliserez pour cela une liste chaînée.

2   Objectifs

A l'issue de cette mission, chacun d'entre vous :

  • sera en mesure d'exploiter les listes chaînées ;
  • aura eu l'occasion d'écrire des tests unitaires pour ses programmes.

3   Préparation, étude et apprentissage

Comment bien préparer la mission?

  1. Assister au cours et regarder les capsules vidéos pour comprendre les notions et concepts qui seront abordés.

  2. Lire attentivement et comprendre le chapitre sur Linked lists dans la partie Objects du syllabus théorie :

    • 7 - Linked lists
      • Embedded references
      • The Node class
      • Linked lists as collections
      • Linked lists and recursion
      • Infinite lists
      • Ambiguity between lists and nodes
      • Modifying lists
      • Wrappers and helpers
      • The LinkedList class
  3. Essayer et comprendre le code développé dans le syllabus et qui se trouve aussi dans l'annexe correspondant :

  4. Dans cette mission, vous devrez de nouveau utiliser le framework unittest pour produire des classes de test. Relisez la documentation si vous aviez du mal à créer des tests unitaires lors de la mission précédente.

  5. Répondre aux questions à choix multiples et aux autres questions de démarrage.

4   Questionnaire de démarrage

Ces questions supposent que vous avez lu le chapitre du syllabus théorique sur les listes chaînées et que vous avez lu et testé le code des classes LinkedList et Node dans l'annexe code des classes LinkedList et Node dans l'annexe correspondante.

4.1   Questions à choix multiples

Les questions à choix multiples de cette mission sont accessibles en ligne depuis https://inginious.info.ucl.ac.be/course/LSINF1101-PYTHON/Session11_QCM.


        
        

4.2   Questions ouvertes

4.2.1   Notions théoriques

Répondez aux questions suivantes:

  1. Qu'est-ce qu'une liste chaînée?
  2. Qu'est-ce qu'une structure de données? Donnez un exemple.
  3. Expliquez la différence entre un noeud (Node) et sa cargaison (cargo).
  4. Expliquez la différence entre un noeud (Node) et une liste chainée (LinkedList).
  5. Dans le livre et le cours magistral, la notion d'une liste chaînée a d'abord été expliqué sans la classe LinkedList, simplement en chaînant des noeuds l'un à l'autre. Pourquoi avons nous alors besoin d'une classe LinkedList?
  6. Expliquez et donnez un exemple du caractère ambiguë d'un noeud.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

4.2.2   Utilisation d'une LinkedList

Question 1 : Manipuler une liste vide

Cette question concerne l'utilisation de la classe LinkedList dont le code se trouve dans l'annexe suivante du syllabus : Appendix - Source code of linked lists

Utilisez la classe LinkedList pour créer une liste chaînée vide l.

 
 

Donnez une instruction Python pour imprimer le contenu de cette liste l.

 
 

Quel résultat sera affiché si on essaie d'imprimer la liste l avec l'instruction print(l)? Expliquez.

 
 

Donnez une instruction Python pour imprimer la taille de cette liste l .

 
 

Quel résultat sera affiché si on essaie d'imprimer la taille avec l'instruction print(l.__length)? Expliquez.

 
 

Question 2 : Remplir la liste

Pour ajouter des éléments à une liste vide, quelqu'un a écrit les instructions suivantes:

l = LinkedList()
l.add(3)
l.add(2)
l.add(1)
l.print()

Mais quelqu'un d'autre à écrit:

l = LinkedList()
l.add(Node(3))
l.add(Node(2))
l.add(Node(1))
l.print()

Dans les deux cas, exécuter l'instruction l.print() affichera [ 1 2 3 ].

Lequel des deux fragments de code ci-dessus vous semble correct? Pourquoi l'autre imprime quand-même le même résulat?

Indice : qu'est-ce qui se passe si on exécute l'instruction print(Node(Node(Node(1))))? Pouvez-vous expliquer?

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

4.2.3   Imprimer une liste chaînée

Dans le code donné dans l'annexe Appendix - Source code of linked lists la méthode print() de la classe LinkedList imprime les éléments d'une liste chaînée, séparés par une espace. Par exemple:

>>> l = LinkedList()
>>> l.add(3)
>>> l.add(2)
>>> l.add(1)

>>> l.print()
[ 1 2 3 ]

Or, normalement la convention est de séparer les éléments d'une liste par des virgules. Ajoutez une nouvelle méthode print_avec_virgule() dans la classe LinkedList qui imprime la liste comme suite:

>>> l.print_avec_virgule()
[ 1, 2, 3 ]

Attention: il n'y a pas de virgule après le dernier élément ou si on imprime une liste vide.

>>> l = LinkedList()
>>> l.print_avec_virgule()
[ ]

4.2.4   Imprimer une liste chaînée (généralisation)

Généralisez la méthode print_avec_virgule de l'exercice précédente par une méthode print_avec_separateur qui peut prendre n'importe quelle séparateur. Par exemple:

>>> l = LinkedList()
>>> l.add(3)
>>> l.add(2)
>>> l.add(1)

>>> l.print_avec_separateur(", ")
[ 1, 2, 3 ]
>>> l.print_avec_separateur(" ")
[ 1 2 3 ]
>>> l.print_avec_separateur(" - ")
[ 1 - 2 - 3 ]

4.2.5   Initialiser une liste chaînée


        
        

4.2.6   Supprimer un élément


        
        

4.2.7   Ajouter un élément à la fin

Ajoutez à la classe LinkedList une méthode add_to_end(self, cargo) pour ajouter un noeud en queue de la liste. Ajoutez d'abord un nouvel attribut last dans la méthode d'initialisation pour garder une référence vers ce dernier élément. Changez ensuite la méthode add pour assigner cette référence lors de l'ajout du premier noeud, et la méthode remove pour remettre cette référence à None lorsque la liste est de nouveau vide. Implémentez ensuite la méthode add_to_end.

Étapes de l'ajout d'un noeud dans une liste chainée :

  1. Créer un nouveau nœud (new_node) composé de la valeur à ajouter dans la liste.
  2. Parcourir la structure pour identifier le nœud précédant l’emplacement où insérer new_node.
  3. Pour ne pas perdre la référence vers le nœud suivant, faire pointer new_node.next vers le nœud qui suit le nœud courant .
  4. Insérer new_node (cas général, attention aux cas particuliers), en faisant pointer le nœud courant vers new_node.
  5. Mettre à jour les attributs de la classe le cas échéant (taille, tête de liste, etc.).

Pour plus de détails sur les étapes, allez voir le catalogue : Ajout d'un noeud dans une liste chainée .

4.2.8   Supprimer un élément à la fin

Est-ce facile d'implémenter une méthode remove_from_end(self, cargo) pour supprimer un élément de la queue d'une LinkedList? Expliquez en mots comment vous feriez.

 
 
 
 
 
 
 
 
 
 

4.2.9   Imbriquer une classe dans une autre

En Python il est possible d'imbriquer une classe dans une autre. Ceci peut être utile si une classe n'est utilise que par une seule autre classe. C'est le cas ici avec la classe Node. Ce n'est qu'une classe auxiliaire pour la classe LinkedList. Adaptez le code de votre classe LinkedList en imbriquant le code de la classe Node dedans. Il suffit d'indenter le code de la classe Node et de changer chaque référence à la classe Node à l'interieur de la classe LinkedList par self.Node.

Quels sont les avantages et désavantages d'imbriquer la classe Node dans la classe LinkedList?

 
 
 
 
 
 
 
 
 
 

4.2.10   Insérer un élément

Considérez qu'on désire utiliser la classe LinkedList pour stocker une liste de strings. On souhaite qu'elle soit en permanence en ordre alphabétique croissant.

  1. Dessinez complètement une telle liste chainée contenant les trois strings "abc", "def" et "xyz".

     
     
     
     
     
     
     
     
  2. Expliquez en français et dessinez les opérations à effectuer pour ajouter un Node contenant "aaa" dans cette liste.

     
     
     
     
     
     
     
     
  3. Même question avec un Node contenant "ghi".

     
     
     
     
     
     
     
     
  4. Même question avec un Node contenant "def".

     
     
     
     
     
     
     
     
  5. Même question avec un Node contenant "zzz".

     
     
     
     
     
     
     
     

        
        

4.2.11   Tests unitaires

Lors de la mission précédente, les tests unitaires avec unittest ont été introduits. Créez un test unitaire pour tester la classe LinkedList. Ce test doit contenir des tests pour les différentes méthodes de la classe LinkedList comme size(), first() ou add(valeur) (code original), remove() (question 4.2.6), add_to_end(valeur) (question 4.2.7) ou insert(valeur) (question 4.2.10). Pour vous mettre sur le bon chemin, votre classe test aura la structure suivante:

import unittest

class LinkedListTest(unittest.TestCase):
    """Classe de test utilisé pour tester la classe LinkedList"""

    def test_size(self):
        """Test de la methode size() de la classe LinkedList."""
        # ... assert*(...) ...

    def test_first(self):
        """Test de la methode first() de la classe LinkedList."""
        # ... assert*(...) ...

    def test_add(self):
        """Test de la methode add(valeur) de la classe LinkedList."""
        # ... assert*(...) ...

    def test_remove(self):
        """Test de la methode remove() de la classe LinkedList."""
        # ... assert*(...) ...

    def test_add_to_end(self):
        """Test de la methode add_to_end(valeur) de la classe LinkedList."""
        # ... assert*(...) ...

    def test_insert(self):
        """Test de la methode insert(valeur) de la classe LinkedList."""
        # ... assert*(...) ...

if __name__ == '__main__':
    unittest.main()
Mission

Mission

1   Description

Lors de cette dernière mission, vous allez implémenter un classement de résultats de coureurs, chaque résultat représenté par un coureur (ayant un certain nom et âge) et le temps effectué par ce coureur. Ces résultats doivent être ordonnés selon leur temps dans une liste chaînée ordonnée. Le meilleur résultat (le coureur avec le meilleur temps) se trouve en tête de la liste. Le résultat du coureur le plus lent se trouve en queue de la liste.

Pour compléter cette mission vous trouverez sur INGInious déjà une grande partie du code nécessaire, sauf l'implémentation complète de la classe Classement que vous devez produire, ainsi que la classe OrderedLinkedList qu'elle doit utiliser. Vous devez également écrire des classes de test détaillées (ClassementTest et OrderedLinkedListTest) en utilisant le framework de test unittest, pour vérifier votre implémentation de la classe Classement.

Vous aurez accès à une implémentation assez complète d'une classe LinkedList sur laquelle vous pouvez vous baser, ou que pouvez étendre, pour implémenter la classe OrderedLinkedList. L'archive qu'on vous fournira contient également une implémentation primitive de la classe Classement à base d'un dictionnaire. Néanmoins, cette implémentation est encore incomplète (elle ne gère pas correctement la position des coureurs dans le classement). Vous devez la remplacer par votre implémentation. Elle permet toutefois au programme de fonctionner. Il suffit d'exécuter la méthode de classe main() de la classe Main dans le fichier main.py: le programme simulera à la console l'ajout d'un nouveau résultat aléatoire toute seconde.

2   Etapes

  1. Avant de commencer lisez bien le code qui vous a été fourni afin que vous comprenez bien sa structure et son comportement.

  2. Vous allez utiliser une liste chaînée ordonnée (OrderedLinkedList ) pour implémenter un tel classement de coureurs. Réfléchissez aux différentes opérations qu'on peut effectuer sur un classement et comment on devrait les implémenter en utilisant une liste chaînée ordonnée.

  3. Avant de commencez à implémenter cette classe Classement, représentez la structure de votre classement comme liste chaînée ordonnée graphiquement, et montrez ce qu'il se passe lorsque, successivement:

    • Vous créez un classement vide;
    • Vous ajoutez un résultat pour le coureur A en tête de classement (méthode add);
    • Vous ajoutez un résultat pour le coureur B en fin de classement (méthode add);
    • Vous ajoutez un résultat pour le coureur C en milieu de classement (méthode add);
    • Vous recherchez les résultats des coureurs A, B et C (méthode get);
    • Vous recherchez les positions des coureurs A, B et C (méthode getPosition);
    • Vous retirez le résultat du coureur B (méthode remove);
    • Vous retirez le résultat du coureur A (méthode remove);
    • Vous tentez de retirer le résultat d'un coureur D (méthode remove).

  4. Implémentez la classe OrderedLinkedList dont vous aurez besoin pour implémenter votre classe Classement.

  5. Implémentez une classe de test OrderedLinkedListTest pour tester le bon fonctionnement de votre classe OrderedLinkedList.

  6. Sur base de notre implémentation incomplète de la classe Classement au moyen d'une dictionnaire, écrivez un squelette de votre classe Classement au moyen d'une liste chaînée ordonnée, qui remplacera la notre. Respectez bien les pré- et post-conditions des différentes méthodes de la classe :

    class Classement :
    
        def __init__(self):
            """
            @pre: -
            @post: un classement vide de taille 0 a été créé
            """
    
        def size(self):
            """
            Méthode accesseur.
            Retourne la taille de ce classement.
            @pre:  -
            @post: Le nombre de résultats actuellement stockés dans ce classement a été retourné.
            """
    
        def add(self,r):
            """
            Ajoute un résultat r dans ce classement.
            @pre:  r est une instance de la classe Resultat
            @post: Le résultat r a été inséré selon l'ordre du classement.
                   En cas d'ex-aequo, r est inséré après les autres résultats de même ordre.
            """
    
        def get(self,c):
            """
            Retourne le résultat d'un coureur donné.
            @pre c est un Coureur
            @post retourne le premier (meilleur) Resultat r du coureur c dans le
                  classement. Retourne None si le coureur ne figure pas (encore)
                  dans le classement.
            """
    
        def get_position(self,c):
            """
            Retourne la meilleure position d'un coureur dans ce classement.
            @pre c est un Coureur
            @post retourne un entier représentant la position du coureur c dans ce classement,
                  à partir de 1 pour la tête de ce classement. Si le coureur figure plusieurs fois
                  dans le classement, la première (meilleure) position est retournée.
                  Retourne -1 si le coureur ne figure pas dans le classement.
            """
    
        def remove(self,c):
            """
            Retire un résultat du classement.
            @pre  c est un Coureur
            @post retire le premier (meilleur) résultat pour le coureur c du classement.
                  c est comparé au sens de __eq__. Retourne c si un résultat a été retiré,
                  of False si c n'est pas trouvé dans la liste.
            """
    
        def __str__(self):
            """
            Méthode magique
            Retourne une représentation string de cet objet.
            @pre:  -
            @post: Retourne une représentation de ce classement sous forme d'un string,
                   avec une ligne par résultat.
            """
    
  7. Ecrivez une classe de test ClassementTest, la plus complète possible permettant de vérifier le bon fonctionnement de votre implémentation de la classe Classement. Utilisez pour cela les méthodes comme assertEqual ou d'autres méthodes définies dans unittest.

  8. Pensez à découper votre classe de test en plusieurs méthodes. Cela facilitera la visualisation des résultats des tests. Vous trouverez sur la tâche INGInious un exemple de classe de test CoureurTest pour la classe Coureur.

  9. Justifiez vos tests dans le fichier README.TXT.

  10. Remplacer votre classe Classement par celle qui vous est fourni et exécutez la méthode main() de la classe Main. Observez que vos classements sont correctement mis à jour. Félicitations!

  11. N'oubliez pas de soumettre votre implémentation des classes OrderedLinkedList et Classement, vos classes de test OrderedLinkedListTest et ClassementTest et votre fichier README.TXT à votre tuteur.

3   Diagramme de classes

Le diagramme de classes suivant résume les différentes classes et attributs qui feront partie de votre solution finale :

/syllabus/info1-exercises/assets/class_diagram_mission11.png

4   Remise de votre solution

Pour cette mission, vous devez soumettre au serveur de soumissions de programmes du cours, vos classes OrderedLinkedList et Classement dans des fichier orderedlinkedlist.py et classement.py, vos classes test OrderedLinkedListTest et ClassementTest dans des fichiers orderedlinkedlisttest.py et classementtest.py, ainsi que votre fichier README.txt.


        
        
Questions complémentaires

Questions complémentaires

1   Méthode __str__ de la classe LinkedList


        
        

Ajoutez également une méthode test correspondante à votre classe test pour vérifier le bon comportement de la méthode __str__.

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

2   Méthode remove_from_end de la classe LinkedList


        
        

Ajoutez également une méthode test correspondante à votre classe test pour vérifier le bon comportement de la méthode remove_from_end.

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

3   Méthode contains de la classe LinkedList

Ajoutez une méthode contains(e) dans la classe LinkedList qui retourne True si la valeur e se trouve dans la liste et False autrement.

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Ajoutez également une méthode test correspondante à votre classe test pour vérifier le bon comportement de la méthode contains(e). N'oubliez pas de prendre en compte différents cas comme:

* la liste est vide;
* la liste contient un seul élément égal à l'élément cherché;
* la liste contient un seul élément différente de l'élément cherché;
* la liste contient différents fois un même élément;
* la liste contient différents fois l'élément cherché.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

4   Lost Children


        
        

5   Classe LinkedList


        
        

6   Turing Machine


        
        

7   Liste doublement chaînée

Adaptez le code de la classe LinkedList pour créer une classe DoubleLinkedList représentant une liste doublement chaînée. Pour chaque noeud, en plus d'avoir un lien vers le noeud suivant, on ajoute un lien vers le noeud précédent. Ceci permet de parcourir la liste dans les deux sens: avancer en suivant la référence vers le noeud suivant, ou reculer en suivant la référence vers le noeud précédent. Votre classe DoubleLinkedList doit au moins fournir les méthodes suivantes:

  • add(e) pour ajouter un élément e en tête de la liste;
  • add_to_end(e) pour ajouter un élément e en fin de la liste;
  • remove_at_start() pour supprimer l'élément en tête de la liste;
  • contains(e) pour vérifier si l'élément e se trouve dans la liste;
  • size() retourne la taille de la liste;
  • isEmpty() vérifie si la liste est actuellement vide.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Ecrivez également une classe test unitaire TestDoubleLinkedList pour vérifier le bon comportement des différentes méthodes de la classe DoubleLinkedList. Cette classe test doit contenir des tests pour les différentes méthodes de la classe DoubleLinkedList.

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

8   Méthode remove de la classe DoubleLinkedList

Au code de la liste doublement chaînée de la question complémentaire précédente, ajoutez une méthode remove(e) pour supprimer la première occurrence de e de la liste doublement chainée.

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Ajoutez également une méthode test correspondante à votre classe test pour vérifier le bon comportement de la méthode remove.

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<string>

<string>

<string>

Table des matières

Évaluation

Étapes d'évaluation du concept d'une affectation

Étapes d'évaluation du concept d'une affectation

  1. Pour chaque sous-expression à droite du signe égal :
    1. Évaluer le type de la sous-expression ;
    2. Déterminer l’ordre de priorité des opérateurs ;
    3. Effectuer les opérations en fonction du type des opérandes.
  2. Évaluer l’expression finale et son type
  3. Affecter (assigner) la valeur à la variable
/syllabus/info1-exercises/assets/slwe/read-assign.png
Étapes d'évaluation du concept d'une instruction conditionnelle

Étapes d'évaluation du concept d'une instruction conditionnelle

  1. Identifier les instructions des différentes branches
  2. Evaluer la condition
  3. Tracer la branche sélectionnée :
    1. Si True, suivre la branche vraie,
    2. Si False, suivre les branches elif suivantes ou else s’il y en a une. Ne rien faire sinon.
/syllabus/info1-exercises/assets/slwe/read-cond2.png
Étapes d'évaluation du concept d'une boucle

Étapes d'évaluation du concept d'une boucle

  1. Identifier la boucle
    1. Instruction de début
    2. Instruction de mise à jour (update)
    3. Condition de fin (ou de continuation)
    4. Corps qui sera répété
  2. Tracer la boucle
/syllabus/info1-exercises/assets/slwe/lecture_boucle_1.png /syllabus/info1-exercises/assets/slwe/read-loop.png
Étapes d'évaluation du concept d'une fonction

Étapes d'évaluation du concept d'une fonction

  1. Identifier la définition de la fonction appelée
  2. Lire la spécification, l’en-tête et le corps de la fonction
  3. Vérifier les arguments dans l'appel de la fonction
    1. le nombre d'arguments respecte l'en-tête
    2. les valeurs et types des arguments respectent les spécifications
  4. Déterminer l'effet de la fonction (valeur et type de retour, effet de bord, affichage, changement d'état)
  5. Tracer le corps de la fonction
/syllabus/info1-exercises/assets/slwe/read_func_print.png /syllabus/info1-exercises/assets/slwe/read_func_return.png
<string>

Étapes d'utilisation du concept d'une affectation

Étapes d'utilisation du concept d'une affectation

  1. Déterminer l’expression pour calculer la valeur à affecter ;
  2. Déterminer l’identifiant de la variable à modifier ;
  3. Écrire l’expression Python avec les bons opérateurs ;
  4. Vérifier que les types des opérandes soient bien compatibles avec les opérateurs ;
  5. Vérifier si la valeur de l’expression est du type attendu
/syllabus/info1-exercises/assets/slwe/write-assign.png
Étapes d'utilisation du concept d'une instruction conditionnelle

Étapes d'utilisation du concept d'une instruction conditionnelle

  1. Définir tous les cas mutuellement exclusifs nécessaires ;
  2. Les ordonner pour faciliter la lisibilité des conditions ;
  3. Écrire if, la première condition, « : » et les instructions du cas True indentées ensuite ;
  4. S’il y a plus de deux cas, faire de même pour chacune avec elif ;
  5. Finir si nécessaire par else, « : » et les instructions correspondantes.
/syllabus/info1-exercises/assets/slwe/write-cond.png
Étapes d'utilisation du concept d'une boucle while

Étapes d'utilisation du concept d'une boucle while

Boucle while

  1. Définir et initialiser les variables ;
  2. Déterminez la condition d’arrêt (ou de continuation)
  3. Écrire le corps de la boucle (mettre à jour la variable de contrôle jusqu’à la condition d’arrêt si nécessaire).
/syllabus/info1-exercises/assets/slwe/write-loop-while.png
Étapes d'utilisation du concept de boucle for et parcourir une séquence

Étapes d'utilisation du concept de boucle for et parcourir une séquence

  1. Déterminer la séquence à parcourir :

    1. Soit un intervalle avec un pas

      for i in range(a, b, pas) :
         # Corps de la boucle
      
    2. Soit itérer sur les indices ;

      for index in range(len(l)) :
         # Corps de la boucle
      
    3. Soit itérer sur les éléments

      for element in l :
         # Corps de la boucle
      
    4. Et initialiser les variables de parcours en fonction ;

  2. Exprimer la condition de traitement si nécessaire (ou de sortie de boucle si la liste ne doit pas être parcourue en entier)

  3. Écrire le corps de la boucle

  4. Vérifier les cas particuliers (liste vide, bornes de début et fin de parcours, etc).

/syllabus/info1-exercises/assets/slwe/write-for2.png /syllabus/info1-exercises/assets/slwe/write-for1.png
Étapes d'utilisation du concept d'écriture d'une fonction

Étapes d'utilisation du concept d'écriture d'une fonction

  1. Écrire l'en-tête de la fonction
    1. Choisir l'identifiant de la fonction pour qu'il traduise l'intention (snake_case)
    2. Choisir le nombre de paramètres et les identifiants pour qu'ils traduisent leur rôle
  2. Rédiger les spécifications de la fonction
    1. Donner les préconditions sur les paramètres de la fonction et leur type
    2. Donner les postconditions décrivant l'effet, la valeur et le type de retour de la fonction
  3. Écrire le corps de la fonction en respectant les spécifications
    1. Déterminer la logique du programme (affectation, condition, boucle, etc)
    2. Déclarer les variables locales nécessaires
    3. Écrire les instructions du programme
  4. Terminer par un return en fonction des spécifications
    1. Il faut un return pour chaque chemin d’exécution dans la fonction
    2. Pas de return est équivalent à retourner None
/syllabus/info1-exercises/assets/slwe/write-func.png
Étapes d'utilisation du concept de lecture d'un fichier

Étapes d'utilisation du concept de lecture d'un fichier

  1. Ouverture du fichier
    1. Identifier le nom et le chemin du fichier (typiquement dans filename)
    2. Choisir le mode "r" pour la lecture
    3. Ouvrir le fichier avec : with open(filename , mode) as f : ou f = open(filename , mode)
  2. Traitement du fichier en fonction du format
    1. Parcours des lignes : ligne par ligne avec f.readline() en itérant sur les lignes avec for line in f: ou for line in f.readlines())
    2. Traitement des lignes
      1. Retrait des blancs en début et fin de ligne (line.strip())
      2. Séparer les éléments en fonction du format (line.split())
      3. Convertir les éléments en fonction du type attendu
    3. Traiter les erreurs de formatage du fichier (ignorer ligne, raise ValueError) * Trouver l’expression pour écrire une ligne en fonction du format par concaténation
  3. Fermeture du fichier
    1. Avec un with, il n’y a rien à faire
    2. Sinon, avec un f.close()
  4. Gérer les exceptions susceptibles de se produire durant le traitement du fichier (typiquement IOError)
    1. Mettre le code dans un try : … except :
    2. Traiter les exceptions par le suite avec des except error_type: …
/syllabus/info1-exercises/assets/slwe/write-file-read.png
Étapes d'utilisation du concept de l'écriture d'un fichier

Étapes d'utilisation du concept de l'écriture d'un fichier

  1. Ouverture du fichier
    1. Identifier le nom et le chemin du fichier (typiquement dans filename)
    2. Choisir le mode "r" pour la lecture ou le mode "w" pour l'écriture
    3. Ouvrir le fichier avec : with open(filename , mode) as f : ou f = open(filename , mode)
  2. Traitement du fichier en fonction du format
    1. Trouver l’expression pour écrire une ligne en fonction du format par concaténation
    2. Parcourir la structure de données et écrire les lignes au fur et à mesure
      1. Avec f.write()
      2. Prendre en compte les retours à la ligne
  3. Fermeture du fichier
    1. Avec un with, il n’y a rien à faire
    2. Sinon, avec un f.close()
  4. Gérer les exceptions susceptibles de se produire durant le traitement du fichier (typiquement IOError)
    1. Mettre le code dans un try : … except :
    2. Traiter les exceptions par le suite avec des except error_type: …
/syllabus/info1-exercises/assets/slwe/write-file-write.png
Étapes d'utilisation du concept de création et mise à jour d'un dictionnaire

Étapes d'utilisation du concept de création et mise à jour d'un dictionnaire

  1. Déterminer le type des clés et des valeurs du dictionnaire, éventuellement à l’aide d’un dessin ;
  2. Créer un dictionnaire vide (d={}) s’il n’existe pas encore ;
  3. Pour chaque clé à modifier dans le dictionnaire, vérifier si la clé existe dans le dictionnaire
    1. Établir l’expression qui donnera la valeur à mettre dans le dictionnaire
    2. Si non, ajouter la clé au dictionnaire avec une valeur par défaut en fonction du type des valeurs (d[key] = default_val) ou directement la bonne valeur
    3. Si oui, mettre à jour la valeur correspondante à la clé (nouvelle valeur ou valeur modifiée en fonction, par exemple d[key] = new_val ou d[key].append(new_elem))
/syllabus/info1-exercises/assets/slwe/write-dic.png
Étapes d'utilisation du concept de l'écriture d'une classe

Étapes d'utilisation du concept de l'écriture d'une classe

  1. Bien nommer la classe
    1. Utiliser un substantif qui décrit le type d'objet
    2. Utiliser du CamelCase si le nom est composé de plusieurs mots
  2. Déterminer les attributs et méthodes en fonction de ce que représente cette classe
    1. Déterminer le nombre et les types des attributs
    2. Déterminer le nombre et les objectifs des méthodes
  3. Créer la méthode d’initialisation __init__
    1. Entête :
      1. Ajouter self comme premier paramètre
      2. Déterminer les types et les identifiants des paramètres pour qu’ils traduisent leur rôle
    2. Pour chaque attribut nécessaire :
      1. Choisir un identifiant qui traduise son rôle (le même que le paramètre associé sipossible)
      2. Trouver l’expression pour l’initialiser en utilisant (ou non) les paramètres (self.attr = expression)
  4. Pour chaque autre méthode d’instance
    1. Ecrire l'entête :
      1. Donner un identifiant en snake_case à la méthode qui traduise son rôle
      2. Ajouter self comme premier paramètre
      3. Déterminer les types et les identifiants des paramètres pour qu’ils traduisent leur rôle
    2. Ajouter au moins un test pour cette méthode
    3. Dans le corps de la méthode :
      1. Utiliser self.attribut pour accéder à la valeur d’un attribut
      2. Pour appeler une autre méthode de la même classe écrivez self.autre_méthode()
      3. Si la méthode doit retourner un résultat ne pas oublier return et bien réfléchir à l’expression et au type de la valeur retournée
  5. Créer la méthode __str__
    1. Entête :
      1. Écrire l’entête def __str__(self)
    2. Déterminer l’expression pour représenter l’objet au format désiré en utilisant les bons attributs
      1. Concaténer les attributs via + self.nom_de_variable +
      2. Attention à bien convertir des valeurs qui ne seraient pas des strings avec l’instruction str(otherType)
  6. Créer la méthode __eq__
    1. Entête :
      1. Écrire l’entête def__eq__(self,autre)
    2. Vérifier que le paramètre autre est bien une instance de cette classe avec type() ou isinstance(autre, ClassName)
    3. Comparer individuellement l’égalité des valeurs des attributs désirés
  7. Tester la classe en exécutant les tests que vous avez ajouté pour ses différentes méthodes.
/syllabus/info1-exercises/assets/slwe/write-class.jpeg /syllabus/info1-exercises/assets/slwe/write-class-2.png
Étapes d'utilisation du concept de l'ajout d'un noeud dans une liste chainée

Étapes d'utilisation du concept de l'ajout d'un noeud dans une liste chainée

  1. Créer un nouveau nœud (new_node) composé de la valeur à ajouter dans la liste.
  2. Parcourir la structure pour identifier le nœud précédant l’emplacement où insérer new_node
  3. Pour ne pas perdre la référence vers le nœud suivant, faire pointer new_node.next vers le nœud qui suit le nœud courant
  4. Insérer new_node (cas général, attention aux cas particuliers), en faisant pointer le nœud courant vers new_node
  5. Mettre à jour les attributs de la classe le cas échéant (taille, tête de liste, etc.)
/syllabus/info1-exercises/assets/slwe/liste-chainee-ajout-1.png /syllabus/info1-exercises/assets/slwe/liste-chainee-ajout-2.png
Étapes d'utilisation du concept du retrait d'un noeud dans une liste chainée

Étapes d'utilisation du concept du retrait d'un noeud dans une liste chainée

  1. Identifier la valeur associée au nœud à retirer
  2. Parcourir la structure pour identifier le nœud précédant l’emplacement du nœud à supprimer
  3. Retirer le nœud correspondant (cas général) en faisant pointer le nœud courant vers le nœud suivant le nœud à supprimer
  4. Mettre à jour les attributs de la classe le cas échéant (taille, tête de liste, etc.)
/syllabus/info1-exercises/assets/slwe/liste-chainee-retrait-1.png /syllabus/info1-exercises/assets/slwe/liste-chainee-retrait-2.png