<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 :

  • savoir effectuer son login
  • s'y retrouver dans les icônes, les fenêtres, etc. sur un poste de travail informatique
  • savoir utiliser le navigateur (browser) Internet
  • savoir consulter le livre de référence du cours d'informatique :
    https://self-learning.info.ucl.ac.be/index/info1-theory

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.

 
 
 
 
 
 

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 ?

 
 
 
 
 
 

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!. 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









Lucie veut prendre un bain, mais sa baignoire est trouée. Si elle ouvre le robinet, 12L coulent dans la baignoire chaque minute, et 1L s'écoule par le trou chaque minute. Vous aimeriez savoir combien de minutes elle devra attendre pour que la baignoire contienne au moins 80L d'eau et aussi simuler la croissance du volume de l'eau en Python.

D'abord, calculez le nombre de minutes nécessaires pour avoir exactement 80L dans la baignoire (exprimé en nombre à virgule flottante) et l'enregistrer dans une variable nommée filled_time. Ensuite, enregistrez le volume d'eau actuel dans une variable nommée water_vol (qui commence à 0) et utilisez une boucle for dans laquelle, à chaque itération (représentant chaque minute), les volumes d'eau s'écoulant du robinet ou par le trou sont ajoutés/retirés du volume d'eau total. En d'autres termes, à chaque itération, water_vol devrait augmenter de 12L et diminuer d'1L.

La boucle for devrait s'arrêter à la première itération où le volume d'eau dépasse les 80L. Ceci peut être calculé à partir de filled_time.

Note: vous pouvez arrondir un nombre à virgule flottante au premier integer plus grand en utilisant le code suivant :

float_nb = 3.14\n"
int_nb = ceil(float_nb)  # `int_nb` is equal to 4









<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 ___________:
    ______________







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.

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):
        for y in range(1,max):
           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 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("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

Dans le programme ci-dessous, quelle ligne faut-il écrire pour afficher la longueur de la chaîne de caractères s ?

s = "Informatique1"

Question 3

Dans le programme ci-dessous, quelle ligne faut-il écrire pour afficher la chaîne en majuscules ?

s = "Informatique1"
.

Question 4

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

  • 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")
 
 

  • Afficher une liste des positions des traits d'union (sur les exemples, [7,10], [6,9])
 
 
 
 

  • Afficher le mot avant le premier trait d'union. (Sur les exemples, "Louvain", "Braine")
 
 
 
 

Question 4

La fonction max_index(lst) doit retourner l'index de l'élément avec la plus grande valeur dans une liste. La valeur None doit être retournée quand la liste est vide. Définissez cette fonction.


        
        

 
 
 
 

Question 5

Écrivez une fonction triangle(n) qui pour un nombre entier donné n, retourne la liste de listes imbriquées

[ [ 0 ],
  [ 0, 1 ],
  [ 0, 1, 2 ],
  ...,
  [ 0, 1, 2, ..., n ] ]


        
        

Question 6

Écrivez une fonction carre(n) qui pour un nombre entier donné n, retourne 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 ] ]


        
        

Question 7

É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 ] ]


        
        

Question 8

É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 9

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.


        
        

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.

  1. Chargez le fichier exemples.py dans la tâche sur INGInious (plus bas). Ecrivez toutes les fonctions demandées durant cette mission dans ce fichier. Vous trouverez dans ce fichier plusieurs chaînes de caractères représentants des séquences ADN que vous pouvez réutiliser pour tester vos fonctions.

  2. 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.

  3. 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.

  4. 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.

  5. 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.

  6. Dans les séquences d'ADN, on retrouve parfois des palindromes. Un palindrome est un mot dont l'ordre des caractères reste le même qu'on le lise de gauche à droite ou de droite à gauche, comme "radar" ou "kayak". Une séquence ADN telle que CTAGGATC est un exemple de palindrome. A titre d'exemple, le plus long palindrome de la séquence ACCTGTTAGGATTC est TTAGGATT. Certains palindromes ont un rôle particulier d'un point de vue biologique et il est intéressant de pouvoir trouver dans une séquence donnée le plus long palindrome.

    Votre dernier objectif dans cette mission est d'écrire la fonction plus_long_palindrome qui prend comme argument une chaîne de caractères et retourne une chaîne de caractères contenant le plus long palindrome de la chaîne passée en argument. Dans cette phase de réalisation, nous considérons qu'un caractère unique est lui-même un palindrome. Lorsque la fonction ne trouve aucun palindrome dans une chaîne de caractères, elle devra retourner "".

    En Python, il existe une construction pour extended slices, qui n'a pas été discuté pendant le cours et qui n'est pas discuté dans le syllabus. Il n'est pas permis d'utiliser cette construction.

    Détecter le plus long palindrome dans une chaîne de caractères est un problème compliqué. En informatique, lorsque l'on est face à un problème compliqué, la meilleure approche pour le résoudre est de le découper en petits problèmes plus simples. Il suffit ensuite d'écrire une fonction pour résoudre chaque petit problème et de combiner ces fonctions pour résoudre le problème compliqué.

    Pour rechercher le plus long palindrome, une piste est de d'abord écrire une fonction permettant d'extraire d'une chaîne de caractères de longueur n les sous-chaînes de longueur n-1, n-2, ...

Remise de votre solution

Pour cette mission, vous devez soumettre votre fichiers 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)
plus_long_palindrome(text)

        
        
Questions complémentaires

Questions complémentaires

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.


        
        
<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 trouver l'emplacement 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

Donnée est une liste d'événements qui ont lieu sur certains coordonnées. Un exemple d'une telle liste est la suivante:

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

Donnée est une coordonnée (i,j), créez une fonction count(events,i,j) pour calculer le nombre d'événement sur cette coordonnée.


        
        

Question 2

Étant données deux listes ordonnées de nombres entiers, 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 ordonnées [-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 idée pour calculer cette liste 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 deuxième partie qu'on n'a pas encore regardé. 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 3

Dans les exercices suivants, on va étudier une répresentation d'un ensemble de chaînes de caractères et un ordre de ces chaînes. Cette répresentation se compose d'une liste de tuples; dans chaque tuple, le premier élément contient une chaîne de caractères; le deuxième élément contient la position de l'élément suivant dans l'ordre voulu. Par exemple :

l = [ ( "", 2 ), ( "Bertram", 5 ), ( "Anna", 1 ), ( "Xavier", None ), ( "Nicolas", 3 ), ( "Dominic", 4 ) ]

On suppose que le premier tuple correspond toujours à la chaîne de caractères vide; si il n'y pas un élément suivant, on utilise None. Notez que dans la liste, on peut avoir seulement un élément None.

L'ordre des chaînes de caractères indiqué par les nombres entiers dans cette liste est ["Anna","Bertram","Dominic","Nicolas","Xavier"] -- par conséquent, l'ordre alphabétique.

Étudiez maintenant la spécification suivante d'une fonction is_sorted_tuple_list(l).

def is_sorted_tuple_list ( l ):
    """ Détermine si l se compose d'une liste de tuples ordonnés par ordre alphabétique.

    Une liste est considérée ordonnée par ordre alphabétique si e[0] < l[e[1]][0], pour tous
    les éléments de la liste tels que e[1] != None; en plus, l[i][0] doit correspondre à "";
    il ne peut y avoir qu'un seul tuple dans la liste pour lequel 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.
    Returns:
        True si l se compose d'une liste de tuples (chaîne de caractères, nombre entier) ordonnés, False si non.
    """

Écrivez quelques tests en utilisant assert pour évaluer l'exactitude de cette fonction.

 
 
 
 
 
 
 
 
 
 

Question 4

Faites une implémentation de la fonction is_sorted_tuple_list et évaluez-la en utilisant les tests d'exercice 3.

 
 
 
 
 
 
 
 
 
 

Question 5

Étudiez la spécification de la fonction suivante.

def get_index ( l, s ):
    """ Retourne l'indexe de la plus grande chaîne de caractères plus petite que s dans la liste l.

    Une chaîne de caractères en l est plus petite que s, si cette chaîne est plus petite dans l'ordre alphabétique ou égale.

    Args:
        l:  une liste de tuples, dont chacun se compose d'une chaîne de caractères et un nombre entier ou None;
            la première chaîne de caractères en l est "".
        s:  une chaîne de caractères.
    Retourne:
        L'indexe de la chaîne de caractères la plus grande en l, mais plus petite que s.
    """

Écrivez quelques tests pour évaluer l'exactitude de cette fonction.

 
 
 
 
 

Question 6

Créez une implémentation de la fonction get_index et évaluez-la avec vos tests.

 
 
 
 
 
 
 
 
 
 

Question 7

Étudiez la spécification de la fonction suivante.

def add ( l, s ):
    """ Ajoute la chaîne de caractères s à la liste ordonnée de telle sorte que la liste reste ordonnée.
    Si s se trouve déjà dans la liste, la liste n'est pas modifiée.

    Une liste est considérée ordonnée par ordre alphabétique si e[0] < l[e[1]][0], pour tous
    les éléments de la liste tels que e[1] != None; en plus, l[i][0] doit correspondre a "";
    il ne peut y avoir qu'un seul tuple dans la liste pour lequel e[1] == None.

    Si la chaîne s ne se trouve pas déjà dans la liste, la fonction ajoute l'élément à la fin de
    la liste l, de telle sorte que les nombres entiers continuent à indiquer l'ordre alphabétique des chaines
    de caractères.

    Args:
        l: une liste de tuples, dont chacun se compose d'une chaîne de caractères et un nombre entier ou None;
          la première chaîne de caractères en l est "". Les nombres entiers indiquent l'ordre alphabétique
          des chaines de caractères.
        s:  une chaîne de caractères.
    Retourne:
        Rien; l est modifiée comme indiqué.
    """

Écrivez quelques tests pour évaluer l'exactitude de cette fonction.

 
 
 
 
 

Question 8

Écrivez une implémentation de cette fonction et évaluez-la avec vos tests; considérez réutiliser une fonction que vous aviez écrite pour un exercice précédent! Cet exercice est le dernier exercice sur le sujet de listes ordonnées.

 
 
 
 
 
 

Question 9

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 dans cette structure de données. Copiez le code du cours et modifiez-le.


        
        

Question 10

On peut appliquer l'algorithme de question 9 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.

 
 
 

Question 11

On suppose donnés deux noms de cours et une structure de données comme donnée en question 9. Écrivez un algorithme pour retourner tous les noms de cours entre les deux noms spécifiés.

Notez qu'il y a beaucoup d'algorithmes qu'on pourrait utiliser pour cette tâche. On pourrait modifier binary_search, ou utiliser binary_search pour le premier nom, le deuxième nom, etc. Réfléchissez sur les différents algorithmes possibles!

 
 
 
 
 
 
Mission 5

Mission 5

Pour cette mission, vous devez écrire des fonctions et tester leur bon fonctionnement. Comme dans les exercices de préperation, 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

Etape 1

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.

  • É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. Faites attention: commencez avec 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. 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 tous 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().

Etape 5

Écrivez une fonction closest(commune, all_communes) pour calculer la commune la plus proches d'une commune donnée commune. Ajoutez les spécifications pour cette fonction, ainsi que des testes pour vérifier l'exactitude de la fonction, dans une fonction test_closest ().

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 fonctinos. 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)
closest(commune all_communes)

        
        
Questions complémentaires

Questions complémentaires

Question 1

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

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

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 21)

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 y pour une x donnée. Pour l'exemple:

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

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 164)

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.

System Message: WARNING/2 (<string>, line 257)

Explicit markup ends without a blank line; unexpected unindent.

É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 le 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, dans lequel 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 write_coordinates(filename, l) pour créer un fichier qui contient les coordonnées de la liste l dans le format suivant:
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 ci-dessus, et retourne une liste de tuples, comme donnée.

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.


        
        

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])))
else: if 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
  • info: montre le nombre de lignes et de caractères du fichier
  • dictionary: utilise le fichier comme dictionnaire à partir de maintenant
  • search <word>: cherche le mot le plus similaire au mot spécifié dans le dictionnaire
  • 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

En outre, il vous est demandé d'ajouter une commande de votre choix à l'outil.

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

Bienvenue dans votre outil personnalisé!
> file all-words.dat
Loaded all-words.dat
> info
11304 lines
1330218 caracters
> dictionary
Read file as dictionary
> search presbytaerial
Closest word is presbyterial
> search prebyteriaal
Closest word is presbyterial
> exit

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

Le format des dictionnaires est spécifié dans les exercices préparatoires. Pour éviter tout problème avec l'encodage des caractères accentués, votre dictionnaire vérifiera des mots en anglais (sans accents). Si l'utilisateur spécifie un mot qui n'est pas présent dans le dictionnaire, l'outil doit retourner le mot le plus similaire.

La phase de réalisation de cette mission est moins guidée que les précédentes. Par conséquent :

  • Vous pouvez choisir comment définir la similarité entre mots : par exemple, vous pouvez utiliser la fréquence des mots, puisqu'elle est spécifiée dans le fichier dictionnaire.
  • Vous pouvez créer une commande supplémentaire: cela peut être une autre commande mathématique, mais aussi une autre commande liée au dictionnaire.
  • 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. Ce dictionnaire a été construit en se basant sur deux sources d'information : le dictionnaire utilisé 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 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

Donnée sont

  • 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 3

Écrivez un outil qui fait la suivante:

  • 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.

Séparez le programme en fonctions, avec au moins - une fonction create_dictionary(name) pour lire le fichier name et créer le dictionnaire - une autre fonction pour demander les mots à l'utilisateur. Pour simplifier l'exercice, il n'est pas nécessaire de traiter les erreurs.


        
        

Question 4

Donné une structure de données comme la suivante:

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

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 développer un outil qui permet un utilisateur de chercher répétitivement dans un fichier de texte.

Il faut implementer les fonctions suivantes, et les utiliser dans l'outil final:

  • readfile(filename): cette fonction retourne une liste des lignes dans le fichier avec le nom filename. Tous les caractères de chaque ligne doivent être inclus.

  • get_words(line): pour une chaîne de caractères donnée, cette fonction retourne une liste des mots dans la chaîne, en minuscules, et sans ponctuation. Par exemple, pour la ligne

    Turmoil has engulfed the Galactic Republic.
    

    Le résultat est

    ["turmoil", "has", "engulfed", "the", "galactic", "republic"]
    
  • create_index(filename) crée un index pour le fichier avec nom filename. En général, un index pour une texte est une structure de données qui permet de chercher rapidement dans cette texte. Dans cette mission, l'index doit se composer de dictionnaires imbriqués: le premier dictionnaire permit de chercher un mot; pour chaque mot, on utilise un dictionnaire imbriqué pour chercher le nombre d'occurrences dans une ligne. Par exemple, pour ces lignes:

    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 notre index, representée comme dictionnaire, est:

    {"while": {0: 1}, "the": {0: 2, 1: 1}, "congress": {0: 1}, \
     "of": {0: 1, 1: 1}, "republic": {0: 1}, ... , "jedi": {2: 1}, ...}
    

    Ici, le dictionnaire contient tous les mots; dans le dictionnaire, "the" : {0: 2, 1: 1} indique que le mot the est associé à deux lignes; il y a deux occurrences dans la ligne avec index 0 et une occurrence dans la ligne avec index 1.

    La fonction doit retourner les dictionnaires imbriqués.

  • get_lines(words,index) retourne les identifiants des lignes qui contiennent tous les mots spécifiés dans la liste words, en utilisant le dictionnaire contenant l'index index. Par exemple, pour la liste ["the","republic"] la fonction doit retourner la liste [0] (puisque la première ligne contient les deux mots). Plusieurs approches sont possible pour faire cette calculation. Une possibilité est de traverser les occurences du premier mot, et de vérifier si on trouve dans ces lignes aussi les autre mots, en utilisant l'index de chaque mot. Il est recommandé de créer des fonctions supplémentaires.

Après avoir demandé le nom d'un fichier, dans une boucle infinie, l'interface doit demander à l'utilisateur de donner une liste de mots en utilisant la fonction input; chaque fois, l'outil cherche les lignes dans lequelles tous les mots spécifiés sont présents, et imprime ces lignes.

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

Pour toutes les fonctions spécifiées ci-dessus, il faut écrire des tests pour vérifier que les fonctions sont correctes. 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.

L'outil doit bien traiter les erreurs (un fichier qui n'existe pas, on cherche un mot qui n'existe pas, ...)

Dans cette mission, nous attendons que vous faites un effort pour produire de code qui est bien lisible. Faites attention que:

  • il y a des commentaires?
  • il y a des pre/post conditions, ou un docstring de style Google?
  • les variables ont des noms bien comprehensibles?
  • les fonctions ne sont pas trop longues?
  • vous pouvez suivre la logique du programme?

Remise de votre solution

Pour cette mission, vous devez soumettre:

  • un fichier search.py avec tout votre code
  • un fichier test.py avec les tests
  • 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

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.

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;
    • constructeur et méthode d'initialisation d'une classe;
  • pourra faire la distinction entre:
    • la référence à un objet et l'objet lui-même;
    • l'égalité superficielle et profonde entre deux objets;
    • une copie superficielle et profonde d'un objet.
  • aura approfondi sa connaissance des facilités de manipulation de texte en Python, et en particulier la conversion automatique par la méthode spéciale __str__;
  • aura écrit un premier programme utilisant des objets en Python;
  • aura réalisé quelques tests de classes simples.

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:

Questionnaire de démarrage

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


        
        

Questions ouvertes

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 du score moyen que l'étudiant a obtenu sur les 3 tests.
        @pre: les variables d'instance test1, test2 et test3
              contiennent des valeurs de type int
        @post: retourne la valeur 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("Votre score moyenne est " + str(student.average_score()))
student2 = student
print("Votre score moyenne 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éthodes d'instance**
 
 
 
 
**Référence à un objet et la valeur None**
 
 
 
 
**Référence à self**
 
 
 
 

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.

 
 
 
 
 
 
 
 

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

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)

Considérons 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)        ##7##
print(p1)        ##8##
print(p2)        ##9##
 
 
 

Création de classes

Dans cet exercice, il vous est demandé de créer une classe Student.

Les étudiants sont supposés avoir les caractéristiques suivantes:

  • Un prénom (attribut name)
  • Un nom (attribut surname)
  • Une date de naissance (attribut birth_date)
  • Une adresse mail (attribut email)

Nous créerons les instances de Student avec l'instruction suivante:

stu = Student('firstname', 'surname', 'birthday', 'email')


        
        

Une méthode simple

Considérons à nouveau la classe Pair. Dans cette classe, comment feriez-vous pour écrire une méthode opposite:

def opposite(self):
    """
    @pre        -
    @post   retourne une nouvelle instance de Pair dont les deux
            éléments sont les opposés de ceux de cette paire-ci.
            L'instance appelante reste inchangée.
    """
    # À implémenter

Cette méthode renvoie une nouvelle instance de la classe Pair telle que ses variables d'instance, a et b, valent l'opposé des variables a et b de l'instance qui y fait appel. Voici un exemple de l'utilisation de cette méthode :

p = Pair(10, -2)
print(p)            # affiche "10, -2"
p.a = 12
print(p)            # affiche "12, -2"
q = p.opposite()
print(p)            # affiche "12, -2"
print(q)            # affiche "-12, 2"


        
        

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?

 
 
 
 

Ajoutez une méthode __eq__(self, p) à la classe Pair qui compare la valeur de deux paires, de manière à ce que p1 == p2 retournera True à la ligne ##1##. Pensez à gérer également le cas où p == None.


        
        

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.

Considérez la classe OrderedPair, qui prend comme variable d'instance un objet de type Pair dont la classe se trouve dans la question précédente. Voici la classe OrderedPair :

class OrderedPair:

    def __init__(self):
        self.p = Pair(0, 0)
        self.ordered = True  # vrai si les deux entiers sont ordonnés: p.a <= p.b

    def set_a(self, n_a):
        """
        @pre -
        @post donne au premier élément de la paire la valeur n_a
        """
        # À implémenter

    def set_b(self, n_b):
        """
        @pre -
        @post donne au second élément de la paire la valeur n_b
        """
        # À implémenter

Le but de l'exercice est d'implémenter les méthodes set_a() et set_b(), sans oublier de mettre à jour ordered en fonction des nouvelles valeurs des nombres dans la paire.


        
        

Mission 8

Mission 8

L'objectif principal de cette mission est de définir et d'utiliser trois classes correspondant respectivement à un temps ou une durée (sous la forme heures-minutes-secondes), à une chanson et à un album. 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, au nombre de minutes et de secondes de la chanson, 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, un étudiant pourra se concentrer sur le développement d'une classe tandis que l'autre préparera des tests. Les spécifications des méthodes étant donnée par avance, il est 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? Pour que ces questions aient un sens, il est également primordial de bien spécifier les méthodes.

(Remarque: lors de cette mission on n'utilisera pas encore les 'tests unitaires'; vous pouvez tester votre code comme vous l'avez fait lors des missions précédentes. Les tests unitaires seront introduites dans une mission futur.)

Etapes

  1. Chargez le fichier "music-db.txt". Ce fichier contient une liste de plus de 300 chansons, au format décrit ci-dessus.

  2. Créez une nouvelle classe Duree qui représente une durée exprimée en heures (h), minutes (m) et secondes (s).

  3. Créez une série de tests que vous utiliserez pour tester la classe Duree. Ajoutez des tests au fur et à mesure que vous ajouterez des méthodes à la classe Duree. 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, si votre classe Duree a une méthode ajouter(), vous pourrez implémenter une fonction test_ajouter() pour tester les différents scénarios d'utilisation de la méthode ajouter() de la classe Duree.

  4. Dans la classe Duree, définissez une méthode d'initialisation avec comme paramètres __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. Veillez à la spécification et vérifiez que les conditions requises soient respectées.

  5. Dans la classe Duree, ajoutez des méthodes correspondant aux spécifications suivantes:

    def toSecondes(self) :
        """
        Retourne le nombre total de secondes de cette instance de Duree (self).
        """
    
    def delta(self,d) :
        """
        Retourne la différence entre cette instance de Duree (self) et la Duree d passée en paramètre,
        en secondes (positif si ce temps-ci est plus grand).
        """
    
    def apres(self,d):
        """
        Retourne True si cette instance de Duree (self) est plus grand que la Duree d passée en paramètre;
        retourne False sinon.
        """
    
    def ajouter(self,d):
       """
       Ajoute une autre Duree d à cette instance de Duree (self).
       Corrige 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).
       """
    
    def __str__(self):
        """
        Retourne cette durée sous la forme de texte "heures:minutes:secondes".
        Astuce: la méthode "{: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.
        """
    
  6. Ecrivez des fonctions test pour chacune de ces méthodes de la classe Duree, exécutez-les et assurez-vous que les résultats sont conformes aux spécifications, en corrigeant au besoin.

  7. Créez une nouvelle classe Chanson représentant une chanson, caractérisée par un titre t (string), un auteur a (string) et une durée d (Duree). Définissez une méthode d'initialisation avec comme paramètres __init__(self, t, a, d).

  8. Dans la classe Chanson, implémentez une méthode de conversion __str__ correspondant à la description suivante:

    def __str__(self):
        """
        Retourne un String décrivant cette chanson sous le format "TITRE - AUTEUR - DUREE".
        Par exemple: "Let's_Dance - David_Bowie - 00:04:05"
        """
    
  9. Créez une série de tests que vous utiliserez pour tester la classe Chanson.

  10. Créez une classe Album représentant un album contenant une ou plusieurs chansons.

  11. En plus d'une méthode d'initialisation pour créer un album vide, cette classe contient une méthode add(self,chanson) pour ajouter une chanson à un album. Cette méthode retourne False si lors de l'ajout d'une chanson l'album a atteint 100 chansons ou la durée dépasserait 75 minutes. Sinon la chanson est rajoutée et la méthode add retourne True.

  12. Dans la classe Album, implémentez également une 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
    
  13. Créez une série de tests pour tester la classe Album.

  14. 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;
    4. lorsque le nombre de chansons stockés dans un 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-dessous;
    5. poursuit la lecture du fichier et l'ajout des chansons dans un album suivant;
    6. répète ces étapes jusqu'à ce que le fichier edt 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

Remise de votre solution

Pour cette mission, vous devez soumettre votre programme mission8.py, un 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 au moins contenir les 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

SMS Store

Create a new class SMSStore. The class will instantiate SMS_store objects, which can store SMS messages, similar to an inbox or outbox on a cellphone:

my_inbox = SMS_store()

This store can hold multiple SMS messages (its internal state will just be a list of messages). Each message will be represented as a tuple: (has_been_viewed, from_number, time_arrived, text_of_SMS)

The inbox object should provide these methods:

my_inbox.add_new_arrival(from_number, time_arrived, text_of_SMS)
    # Makes a new SMS tuple, and inserts it after the other messages
    # in the store. When creating this message,
    # its has_been_viewed status is set False.

my_inbox.message_count()
    # Returns the number of sms messages in my_inbox

my_inbox.get_unread_indexes()
    # Returns list of indexes of all not-yet-viewed SMS messages

my_inbox.get_message(i)
    # Return (from_number, time_arrived, text_of_sms) for message[i]
    # Also change its state to "has been viewed".
    # If there is no message at position i, return None

my_inbox.delete(i)
    # Delete the message at index i

my_inbox.clear()
    # Delete all messages from inbox

Write the class ``SMS_store``, create a message store object,
write tests for each of the above methods, and implement the methods.


        
        

Création d'objets depuis un fichier

Dans cet exercice, il vous est demandé de créer une fonction créant des instances de la classe Student basées sur les informations contenus dans un fichier, et les renvoyant dans une liste. Ceci afin de récupérer les notes de l'interros des différents participants.

Voici le constructeur de la classe Student:

class Student:
    def __init__(self, firstname, surname, mark):
        self.firstname = firstname
        self.surname = surname
        self.mark = mark

Le fichier suit le format suivant:

Kim Mens 12
Charles Pecheur 13
Siegfried Nijssen 18

Implémentez la fonction marks_from_file(filename) qui lit, ligne par ligne, le fichier nommé filename, et qui retourne une liste d'instances de Student, correspondant aux différents lignes du fichier.


        
        

<string>

Table des matières

Mission 9 - Héritage

Mission 9 : Héritage

Mission 9 : Héritage

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'UCL 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.

Objectifs

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

  • 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;
    • les notions d'héritage, de polymorphisme, et d'hiérarchie de classes;
    • l'utilisation de self et super();
  • sera capable d'utiliser l'héritage pour étendre un programme Python;

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

  • aura appris les notions de variables et méthodes de classe et leur utilité;

  • 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;

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:

Questionnaire de démarrage

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


        
        

Questions ouvertes

Question 1 : 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()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Question 2 : 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 m1 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 m1 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()
 
 
 
 
 
 
 

Question 3 : 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 estVisible(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,lo,la,x,y) :
        """
        @pre lo (longeur) et la (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.longeur = lo
        self.largeur = la

    def __str__(self) :
        return str((self.longeur,self.largeur,self.x,self.y,self.estVisible()))

>>> 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()
 
 
 
 
 
 
 
 

  • estVisible()
 
 
 
 

Question 4 : Variables privés

Pour éviter de rendre accessible les variables x, y et visible à l'extérieur d'une Figure, quelqu'un modifie le code de la classe Figure. Concrètement, pour rendre ces variables privés, on ajoute un __ à leur nom, comme suit :

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 estVisible(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

Malheureusement, le code de la classe Rectangle, qui hérite de la classe Figure ne marche plus maintenant. Quel est le problème?

 
 
 
 

Comment peut-on corriger ce problème? Corrigez le code afin que les instructions suivantes produisent le résultat voulu.

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

Question 5 : Carre

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?
 
 
 
 

Question 6 : 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)
 
 
 
 

Question 7 : Ticket

Complétez la classe Ticket ci-dessous:

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

    __prochainnumero = 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

Description

Pour cette mission, vous disposez au départ d'un programme simple permettant d'imprimer des factures. Ce programme comporte principalement deux classes: l'une représente un Article, c'est-à-dire une ligne dans la facture; l'autre représente une Facture sous forme d'une liste d'articles et offre des méthodes permettant de l'imprimer.

Une classe de test initiale Test est également fournie, elle produit 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 |
===================================================================================

Une version plus étendue de cette classe de test est également fournie; elle vous permettra de tester les extensions que vous devez développer.

Votre objectif principal est de développer des classes qui étendent 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 complet devrait être capable de calculer et générer des factures et bons de livraison tels que celui-ci:

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 |
| 1 * disque dur 350 GB @ 49.99            |      49.99 |      10.50 |      60.49 |
| 3 * souris bluetooth @ 15.99             |      47.97 |      10.07 |      58.04 |
| Réparation (0.75 heures)                 |      46.25 |       9.71 |      55.96 |
| 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 |
===================================================================================

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 ***

Voici les étapes à suivre:

Etape 0

Chargez les fichiers et étudiez leurs contenus. Vous disposez des fichiers suivants:

  1. article.py : cette classe représente un article de la facture. Elle contient un descriptif et un prix et offre des méthodes permettant d'obtenir ces données et de calculer le prix avec TVA. Analysez attentivement le code de cette classe. Remarquez comment les différentes méthodes font appel à prix() . Ceci est important quand on étend cette classe: en redéfinissant prix() on modifiera aussi indirectement les autres méthodes qui y font appel.
  2. facture.py: 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__.
  3. test.py: qui fonctionne avec les classes fournies initialement. Elle produit l'impression reprise dans le premier exemple ci-dessus.

Vous devrez vous-mêmes créer au moins deux classes ArticleReparation et ArticlePiece qui étendent Article, une classe Piece , ainsi que deux méthodes supplémentaires dans Facture , selon les instructions qui suivent.

Etape 1

  • Dans le fichier mission9.py , créez une nouvelle classe ArticleReparation qui étend Article . Cette 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.
  • Modifiez la classe TestFactureInitial ou créez une nouvelle classe teste TestFactureEtape1 pour tester votre classe.

Etape 2

  • Créez une nouvelle classe "Piece" qui représente une pièce que l'on peut facturer. Elle comporte les données suivantes:

    • une description (string), p.ex. 'souris bluetooth';
    • un prix unitaire (float), p.ex. 15.99 Euro;
    • 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 deux paramètres (description, prix) pour les pièces de poids négligeable, non fragiles et à taux de TVA normal.

  • Ajoutez des méthodes accèsseurs (méthodes 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).

Etape 3

  • Créez une nouvelle classe ArticlePiece qui étend Article et représente l'achat d'un nombre donné d'une pièce donnée.
  • Ajoutez une méthode d'initialisation prenant le nombre et la pièce en paramètres, ainsi que des méthodes accèsseurs pour ces deux données.
  • Re-définissez la méthode description() pour fournir un texte reprenant la description de la pièce, le nombre et le 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.
  • Re-définissez la méthode tva() pour appliquer un taux de 6% aux pièces à taux de TVA réduit.
  • Modifiez la classe TestFactureInitial ou créez une nouvelle classe teste TestFactureEtape3 pour tester votre classe.

Etape 4

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

Etape 5

Dans la classe Facture, ajoutez une méthode printLivraison() 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 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 printLivraison() , réutiliser un maximum de méthodes déjà existantes dans la classe Facture .

Finalement, modifiez la classe TestFactureInitial ou créez une nouvelle classe teste TestFactureEtape5 pour tester votre nouvelle méthode.

Remise de votre solution

Pour cette mission, vous devez soumettre toutes les classes de votre programme dans un 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, Piece et ArticlePiece.

Votre fichier test.py doit contenir soit votre classe TestFactureInitial modifiée, soit les classes TestFactureInitial, TestFactureEtape1, TestFactureEtape3 et TestFactureEtape5, 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 illustrer plus haut dans ce document.


        
        

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

Variable de classe

Dans cet exercice, il vous est demandé de programmer une classe Student . Chaque instance de cette classe représente un étudiant, ayant les caractéristiques suivantes :

  • Un prénom
  • Un nom de famille
  • Une date de naissance
  • Un courriel
  • Un NOMA (un numéro d'identification différent pour chaque étudiant et donné à la création de l'objet)

La représentation en format string de cet objet doit être, par exemple : _L'étudiant 27: Hervé Ducobu né le 1 avril, peut être contacté par **herve.ducobu@student.uclouvain.be**_ Pour cela vous êtes invités à implémenter la méthode __str__ .

System Message: WARNING/2 (<string>, line 20); backlink

Inline strong start-string without end-string.

Pour générer un numéro d'identification unique différent pour chaque étudiant, vous êtes conseillé à utiliser une variable de classe pour retenir le dernier numéro généré. Ce numéro est augmenté lors de chaque nouvelle création d'instance de cette classe. Il est déconseillé d'utiliser une variable globale au lieu d'une variable de classe.


        
        

Méthodes de classe

En tant que nouveau manager d'un centre d'expédition d'Amazon, vous devez créer une classe pour représenter les commandes.

Une commande a les attributs suivants :

l'id de l'acheteur ( id_buyer ) l'id de l'objet ( id_item ) la quantité ( quantity ) le prix de l'objet ( price )

Et doit avoir les méthodes suivantes :

  • get_price() : retourne le prix total de la commande
  • __str__() : retourne la commande sous le format : id_buyer, id_item : price * quantity = (price*quantity) Exemple : "12, 32 : 5 * 20 = 100"

Il doit aussi y avoir des méthodes de classe :

get_number_total_command() : retourne le nombre total de commandes effectuées get_total_price() : retourne le prix total de toutes les commandes

Nous allons créer l'objet avec :

command = Command(id_buyer, id_item, quantity_item, price_item)


        
        

Héritage

Commencez par implémenter une classe Animal, qui devrait avoir :

  • un attribut name qui est le nom que le joueur donnera à l'animal
  • un attribut diurnal qui doit être True si l'animal est actif pendant la journée et False s'il est actif pendant la nuit
  • un attribut nb_legs qui représente le nombre de pattes qu'a un animal
  • un attribut asleep qui sera mis à True (resp. False) avec l'appel à la fonction sleep() (resp. wake_up()). Si l'animal essaye de se réveiller alors qu'il n'est pas endormi ou s'il essaye de dormir alors qu'il dort déjà, votre programme devrait lever une RuntimeError.

Seul le name de l'animal doit être passé en argument au constructeur. Nous avons décidé de mettre asleep à False par défaut. Evidemment, comme cette classe représente n'importe quel animal, nous ne connaissons pas la valeur que les autres attributs devraient prendre. La chose la plus logique à faire serait donc de les mettre à None.

Vous implémenterez ensuite trois sous-classes différentes d'Animal réprésentant trois espèces différentes : Lion, Owl et Giraffe. Les valeurs des différents attributs de la classe parent devraient maintenant être définies dans les méthodes d'initialisation.

Lion aura une méthode additionnelle roar(), qui affichera ROARRR!!!.

Owl aura une méthode additionnelle fly(), qui ne fera rien (utilisez l'expression pass pour ne rien faire).

Giraffe aura un attribut additionnel neck_length (en mètres). Cette information sera donnée au constructeur de la classe. Notez que votre code ne devrait pas accepter de valeurs invalides pour cet attribut (les tailles négatives ou exprimées en chaines de caractères par exemple). Levez une ValueError dans le cas où vous avez une valeur invalide.

Vous implémenterez ensuite une dernière classe : Zoo , qui aura une liste de tous les animaux appelée animals comme attribut et une méthode add_animal(animal) pour remplir cette liste. Levez une ValueError si cette méthode reçoit quelque chose d'autre qu'un animal.

On vous demande enfin de définir une fonction create_my_zoo() qui retournera votre zoo contenant un lion, une chouette et deux girafes. Ce sont vos animaux, appelez les comme vous voulez ;)


        
        
<string>

Table des matières

Mission 10 - Polymorphisme

Mission 10

Mission 10

Introduction

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 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 aurez également l'occasion d'écrire des tests unitaires pour vos programmes orientés objets.

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 (en français) sur les tests unitaires avec unittest se trouve également ici Créez des tests unitaires avec unittest

Questionnaire de démarrage

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


        
        

Questions ouvertes

Question 1 : Vocabulaire

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

import unittest
import random

class RandomTest(unittest.TestCase):
    """Clases de test utilisé 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)

# To automatically launch this test when executing this file
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()
 
 
 
 

Question 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()
      

Question 3 : Amazon

As the new manager of an Amazon dispatch center, you have to create a class to represent the commands.

A command have the following attributes :

  • the id of the buyer
  • the id of the item
  • the quantity of the item
  • the price of the item

And must have the following methods :

  • get_price() : return the total price of the command
  • __str__() : return the command on the format : id_buyer, id_item : price * quantity = (price*quantity)

Example : "12, 32 : 5 * 20 = 100"

There must also be class methods :

  • get_number_total_commad() : return the total number of commands made
  • get_total_price() : return the total price of all the commands


        
        

Mission 10

Mission 10

L'objectif de cette mission est de créer des robots 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. On vous fournira une première implémentation basé sur la bibliothèque graphics.py de Python. A vous de proposer une implémentation similaire 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 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 les classes qui vous sont fournies ou 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.

Etapes

Etape 1 : Tester la classe XYRobot

L'objectif de cette première étape sera de créer une classe test TestXYRobot avec des tests unitaires pour une classe XYRobot qui vous est fournie.

  • Avant de commencer, vous devez installer le package graphics.py permettant de dessiner des figures simples dans une fenêtre graphique. Cette bibliothèque 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 .

  • La classe XYRobot utilise aussi des fonctions mathématiques comme math.cos et math.sin ainsi que des constantes mathématiques comme math.pi, fournies par la bibliothèque math.

  • La classe XYRobot (dont l'implémentation se trouve dans le fichier XYRobot.py qui vous est fourni sur le site inginious où vous pouvez remettre votre solution) représente un robot 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 __init__ et __str__ et des méthodes accesseurs et mutateurs, cette classe implémente des méthodes comme:

    moveforward(distance) :

    fait avancer le robot de distance pixels et trace une ligne lors de ce mouvement

    movebackward(distance) :

    fait reculer le robot de distance pixels et trace une ligne lors de ce mouvement

    turnleft() :

    fait tourner le robot de 90 degrés vers la gauche (dans le sens contraire des aiguilles d'une montre)

    turnright() :

    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 d'abord la bibliothèque graphics.py avant d'exécuter ce fichier.

L'implémentation de cette classe XYRobot vous est fournie mais il manque une classe avec des tests unitaires afin de vérifier que le robot bouge et met à jour ses attributs correctement. Implémentez cette classe de test TestXYRobot afin de vérifier le comportement correct des différentes méthodes de la classe XYRobot.

Par exemple, quand on crée un nouveau robot r2d2 = XYRobot("R2-D2") il se trouvera à la position (x=100,y=100) avec comme angle 0 (direction Est). Après avoir exécuté r2d2.moveforward(50) le robot devrait se trouver à la position (x=150, y=100), approximativement, à cause des arrondis dans les calculs. Ensuite, après avoir exécuté r2d2.turnleft() 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.

Etape 2 : implémenter une classe TurtleBot

Dans cette deuxième étape 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 getangle() et position()) et mutateurs, elle doit implémenter les mêmes méthodes :

moveforward(distance) :
fait avancer le robot de distance pixels et trace une ligne lors de ce mouvement
movebackward(distance) :
fait reculer le robot de distance pixels et trace une ligne lors de ce mouvement
turnleft() :
fait tourner le robot de 90 degrés vers la gauche (dans le sens contraire des aiguilles d'une montre)
turnright() :
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é à ce turtle.

Pour tester son comportement correct, on vous fournit une 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.

Etape 3 : étendre 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 action à l'envers (c'est-à-dire de défaire ces actions).

Plus spécifiquement, il faut ajouter les deux méthodes suivantes:

getHistory(self) :

retourne l'historique des actions précédentes, comme une liste du style:

[('forward', 50), ('left', 90), ('forward', 50), ...]

unplay(self) :
rejouer les actions précédentes dans le sens inverse et vider l'historique après avoir rejoué ces actions

Etape 4

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.

Etape 5

Si vous n'avez pas encore utilisé l'héritage lors de l'étape 3, 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.

Etape 6

Rejouez les tests unitaires de l'étape 4 sur les nouvelle classes XYRobot et TurtleBot qui héritent de la 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.

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é à l'étape 5, 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 5, remettez la version de votre 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 5, remettez la version de votre 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.


        
        
<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

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.

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

Préparation, étude et apprentissage

Comment bien préparer la mission?

  1. Assister au cours 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 :

    • 6 - 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.

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.

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.


        
        

Questions ouvertes

0. 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.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

1. Utilisation d'une LinkedList

Question 1a : 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 1b : 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?

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

2. 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()
[ ]

3. 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. Initialiser une liste chaînée

Changez la méthode d'initialisation __init__ de la classe LinkedList (cf. l'annexe Appendix - Source code of linked lists ), afin qu'elle prenne une liste Python comme paramètre pour initialiser la liste chaînée. Attention: le premier élément de cette liste doit devenir le premier élément de la liste chainée, et ainsi de suite. Spécifier bien cette nouvelle méthode __init__ avec des conditions pre et post.

def __init__(self, lst=[]):
    self.__length = 0
    self.__head = None
    # initialiser la liste chainêé avec les éléments de lst ...

Par exemple:

>>> l = LinkedList([1,2,3])
>>> l.print()
[ 1 2 3 ]

>>> l = LinkedList([])
>>> l.print()
[ ]


        
        

5. Supprimer un élément

Ajoutez à la classe LinkedList (cf. l'annexe Appendix - Source code of linked lists ) une méthode remove() pour supprimer le noeud en tête de la liste. Si la liste chaînée était déjà vide, cette méthode ne fait rien.

l = LinkedList()
l.add(3)
l.add(2)
l.add(1)
l.print()
# [ 1 2 3 ]
l.remove()
l.print()
# [ 2 3 ]
l.remove()
print(l.length)
# 1
l.remove()
l.print()
# [ ]
l.remove()
l.print()
# [ ]


        
        

6. 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.

7. 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.

 
 
 
 
 
 
 
 
 
 

8. 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. Adapter 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?

 
 
 
 
 
 
 
 
 
 

9. 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".

     
     
     
     
     
     
     
     

Comment feriez-vous pour écrire dans la classe LinkedList cf. l'annexe Appendix - Source code of linked lists ) la méthode insert dont la spécification est la suivante:

def insert(self,s):
"""
@pre  s est un string à insérer dans la liste chainée;
      self est une liste chaînée dont les noeuds contiennent des strings;
      les noeuds de la liste sont ordonnées en ordre croissant selon les valeurs (strings)
      qu'ils contiennent.
@post Un noeud contenant le String s a été inséré dans la liste de façon
      à ce qu'après l'insertion celle-ci soit toujours en ordre croissant.
"""

Pour rappel, en Python on peut facilement comparer un string avec un autre avec l'opérateur <. Vous pouvez aussi considérez que la classe Node se trouve maintenant à l'intérieur de la classe LinkedList et possède la méthode mutateur suivante:

class Node:

    def set_next(self,node):
        self.__next = node


        
        

10. Tests unitaires

Lors de la mission précédente, les tests unitaires avec unittest ont été introduits. Pour revisiter ce concept, consultez éventuellement un tutoriel online comme https://openclassrooms.com/fr/courses/235344-apprenez-a-programmer-en-python/2235416-les-tests-unitaires-avec-unittest

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 5), add_to_end(valeur) (question 6) ou insert(valeur) (question 9). 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

Cette mission est un peu différente des autres missions. En effet, vous trouverez sur INGInious 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. Comme source d'inspiration on vous donnera également 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. 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.

L'archive contient déjà 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 class main() de la classe Main: le programme simulera à la console l'ajout d'un nouveau résultat aléatoire toute seconde.

Etapes

  1. Lors de la 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 dans la liste selon leur temps. 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.

  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.

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.