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.
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:
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.
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 :
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.
Le travail effectué pendant les phases (a) et (b) et pendant les réunions (A) et (B) a pour but
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.
Le travail de réalisation (c) a un double but:
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.
Le travail effectué pendant la phase (d) et pendant les réunions (C) et (D) a pour but
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.
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.
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.
Il y a deux types d'évaluations notées qui sont prévues dans le cadre du programme de cette année :
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.
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.
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
Conditions à remplir pour pouvoir résoudre le problème :
Si certains d'entre vous ont des difficultés avec un ou plusieurs de ces pré-requis, il est indispensable que le groupe les résolve avant de commencer à travailler.
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 :
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
A l'issue de ce problème, le groupe tout entier :
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.
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.
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
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:
a, b et c sont des variables contenant des nombres entiers quelconques. Comment feriez-vous pour déterminer la médiane de ces trois nombres ? Pour rappel, la médiane d’un ensemble de nombres est la valeur m telle qu’il y a dans l’ensemble autant de valeurs qui sont supérieures ou égales à m que de valeurs inférieures ou égales à m.
Etapes d'une instruction conditionnelle:
Identifier les différent cas possible
Déterminer dans quel ordre les traiter
Ecrire une condition if
if condition_1 : # Instructions pour le cas 1 (considérez que la condition_1 est vraie)
Ecrire une condition elif pour chaque autre cas que vous voulez traiter
elif condition_x : # Instructions pour le cas x
Ecrire une condition else, pour tous les cas non traités précédemment
else : # Instructions pour tous les autres cas
Pour plus de détails sur les étapes, allez voir le catalogue : Instruction Conditionnelle .
Sachant que print(x) permet d’afficher à l’écran la valeur stockée dans la variable x, comment feriez-vous pour afficher à l’écran la table de multiplication par 123 ?
Etapes d'une boucle while:
Pour plus de détails sur les étapes, allez voir le catalogue : Boucle While .
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)
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.
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.
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 !
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 :
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.
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.
The method sum(list) returns the sum of the elements contained in list.
Example: the sum of [1,2,3] is 6
Note that your algorithm should be able to compute the sum even when the list list contains malicious elements (not numbers).
You want to use your computer to easily compute a polynomial with the following form: y = ax6 + bx2 + c. We give you the coefficients (stored in a, b and c) and the variable x and ask you to put the value of the polynomial at abscissa x inside a variable named y.
Note: there is a way to make this shortly in only one line of code.
En mathématiques, la factorielle d'un entier strictement positif x, noté x!`estleproduitdetouslesentiersstrictementpositifspluspetitsouégauxà``x`. La factorielle de 0 est 1. Calculez la factorielle d'un entier x et enregistrez la valeur calculée dans la variable result.
Exemples:
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 :
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/ |
Conditions à remplir pour pouvoir résoudre le problème :
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.
Vous devez lire et comprendre ces parties du syllabus pour pouvoir mener à bien cette mission :
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.
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:
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.
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.
Définissez les concepts suivants :
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
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 ?
Quelle est la relation entre une instruction et une expression ? Donnez des exemples.
Expliquez ce que produisent les instructions suivantes :
Que se passe-t-il si on exécute ce programme ? Comment peut-on le corriger ?
n = input("n = ? ") print("n^2 =", n ** 2)
Expliquez ce que produisent les instructions suivantes :
Que fait le programme suivant ?
for n in [0, 1, 2, 3, 4]: print(10 ** n)
Comment pourrait-on écrire autrement la boucle for ?
Complétez le fragment de code suivant:
# Place dans sum la somme des n premiers entiers pairs strictement positifs n = some_value sum = 0 for ___ in ___________: ______________
Etape d'une boucle for :
Pour plus de détails sur les étapes, allez voir le catalogue .
Un nombre premier est un nombre naturel plus grand que 1 et qui n'a pas d'autres diviseurs positifis à part 1 et lui-même.
Stockez dans is_prime True si le n est un nombre premier et False sinon. is_prime est initialisé à True par défaut.
Les variables ont été initialisées. Ils vous restent à déterminer la séquence, écrire la condition de traitement si nécéssaire, le corps de la boucle et vérifier les cas particulier. Pour plus de détails sur les étapes, allez voir le catalogue .
is_prime = True n = ... #Un entier supérieur à 1
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 :
Cette recherche se fera en énumérant toutes les valeurs possibles de x, y et z et en vérifiant pour chacun triplet de valeurs si l'équation diophantienne est vérifiée (attention, vous ne pouvez pas utiliser les fonctions du package math dans cette mission). Cette technique d'énumération est parfois utilisée dans le domaine de la sécurité informatique pour décoder des messages cryptés sans connaître la clé de cryptage qui a été utilisée. Elle s'appelle attaque par force brute ou recherche exhaustive.
Groupes : A partir de cette deuxième mission, vous travaillerez en binômes de deux étudiants. Associez-vous en binômes au sein de votre groupe ou de votre local. Si vous êtes en nombre impair dans votre local, un étudiant devra travailler seul. Vous devrez travailler avec un étudiant différent chaque semaine; organisez une tournante des binômes.
Organisation : Décidez comment vous allez faire, dans votre sous-groupe, pour travailler à deux : est-ce toujours le même qui travaille à l'ordinateur ou allez-vous alterner au milieu de la mission ? Que fait celui qui n'est pas à l'ordinateur pour aider celui qui l'est ? A quel moment faut-il aller consulter le livre de référence ? Faut-il avoir lu toutes les sections du livre indiquées dans la rubrique Ressources avant de faire le travail ?
Analyse : Considérez le programme ci-dessous :
# Recherche des racines d'une équation a x + b y = c # Charles Pecheur, septembre 2018 solutions = 0 a = int(input("Entrez la valeur du coefficient a : ")) b = int(input("Entrez la valeur du coefficient b : ")) c = int(input("Entrez la valeur du coefficient c : ")) max = int(input("Entrez la valeur maximale pour x et y : ")) for x in range(1, max+1): for y in range(1, max+1): if a*x + b*y == c: print("x =", x, " y =", y) solutions += 1 if solutions == 0: print("Aucune solution trouvee") else: print(solutions, "solutions trouvees")
Ce programme recherche les racines entières de l'équation diophantienne simple ax + by = c. Essayez de le lire et de bien comprendre comment il fonctionne. Dans Thonny, recopiez le programme dans un fichier equation_simple.py (copiez-collez à partir du syllabus) et testez-le en l'exécutant avec différentes valeurs de a, b et c. Vérifiez notamment que l'équation 8 x + 4 y = 1 n'admet aucune solution alors que l'équation 2 x + y = 3 en admet une infinité.
Vous pouvez inspecter les valeurs des différentes variables en affichant le panneau des variables (menu View > Variables) et en exécutant le programme pas à pas (bouton Debug). Attention, vous devez interrompre votre programme en cours d'exécution (bouton Stop) avant de pouvoir lancer une nouvelle exécution.
Vous pouvez maintenant créer un nouveau programme equation.py permettant de trouver des solutions à des équations diophantiennes du type xa + yb = zc.
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 |
Pour cette mission, vous devez soumettre votre programme equation.py et votre fichier README.txt au serveur de soumissions de programmes du cours.
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 ?
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 :
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.
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.
A l'issue de cette mission, chacun d'entre vous :
Vous devez lire et comprendre ces parties du syllabus pour pouvoir mener à bien cette mission :
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.
Les questions à choix multiples de cette mission sont également accessibles en ligne depuis https://inginious.info.ucl.ac.be/course/LSINF1101-PYTHON/Session3_QCM
Définissez les concepts suivants et donnez un exemple :
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 ?
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.)
Ecrivez l'en-tête, la spécification et le corps d'une fonction fact(n) qui calcule et retourne la factorielle de n : n! = n.(n − 1).(n − 2)…1. Veillez à ce que la méthode que vous écrivez respecte bien les spécifications que vous définissez vous-même.
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.
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 * .
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 ?
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.
Dans cette mission, vous allez devoir utiliser la tortue pour dessiner 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.
L'objectif final de cette mission est de produire à l'écran un dessin du drapeau de l'Union Européenne :
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.
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.
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") ?
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].
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.
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.
Ecrivez (et spécifiez) une fonction plus générale three_color_flag(width, color1, color2, color3) qui dessine un drapeau tricolore de couleurs données. belgian_flag peut maintenant être re-défini comme three_color_flag(100, "black", "yellow", "red"). Ecrivez de même des fonctions dutch_flag, german_flag, luxemburg_flag et french_flag qui dessinent les drapeaux des pays voisins de la Belgique. Sur quelle fonction plus générale allez-vous vous baser ?
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.
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 :
[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. |
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)
Pour aller plus loin, vous pouvez créer des fonctions pour dessiner d'autres drapeaux plus complexes, par exemple :
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:
Les équations du second degré sont des équations de la forme suivante:
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 :
Et la seconde racine s'obtient via la formule suivante :
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
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.
A l'issue de ce problème, chacun d'entre vous :
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.
Les questions à choix multiples de cette mission sont également accessibles en ligne depuis https://inginious.info.ucl.ac.be/course/LSINF1101-PYTHON/Session4_QCM
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.
Etant donnée une chaîne de caractères stockée dans une variable l, par exemple, l = "louvain-la-neuve" ou l = "braine-le-compte", comment feriez-vous pour :
La fonction maximum_index(lst) doit retourner l'index de l'élément avec la plus grande valeur dans une liste non vide. Par exemple: maximum_index([0,2,5,3]) doit retourner 2, puisque 5 est la plus grande valeur et apparaît en position 2. Définissez cette fonction.
Nous voulons écrire une fonction positions(s,p) qui pour une chaîne de caractères s et un caractère p retourne la liste des positions où le caractère p apparaît dans s. Par exemple, pour positions("gtagaac","a") le résultat doit être [2,4,5].
def q(c1,c2): return c1.upper () == c2.upper ()
É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.
def mysterieux(n): l = [] for i in range(n): l2 = [] for j in range(n): l2.append ( n ) l.append ( l2 ) return l
Pour un nombre entier donné n, la fonction doit retourner la matrice
[ [ 0, 1, ..., n - 1 ], [ n, n + 1, ..., 2 * n - 1 ], [ 2 * n, 2 * n + 1, ..., 3 * n - 1 ], ..., [ (n-1) * n, (n-1) * n + 1, ..., n * n - 1 ] ]
Par exemple, pour n=4, la fonction retourne
[ [ 0, 1, 2, 3 ], [ 4, 5, 6, 7 ], [ 8, 9, 10, 11 ], [ 12, 13, 14, 15 ] ]
Les séquences d'ADN sont composées d'un suite de caractères A, T, C et G. Pour traiter de telles séquences en Python, le plus simple est de les manipuler comme des chaînes de caractères.
Votre objectif durant cette mission est de développer quelques fonctions permettant de traiter des séquences d'ADN stockées sous la forme de chaînes de caractères.
Toutes les fonctions doivent être écrites dans un fichier avec le nom bioinfo.py. Vérifiez pour chaque fonction que la fonction est correcte en utilisant des exemples!
La première fonction à écrire est la fonction is_adn(s). Elle prend comme argument une chaîne de caractères s et retourne True si la chaîne de caractères contient uniquement les caractères a, t, c ou g (à la fois en majuscules et en minuscules) et False sinon. Une chaîne de caractères vide ("") n'est pas considérée comme étant de l'ADN.
De bons exemples à utiliser pour les tests sont ici: "acgac", "AcaA", aAaza, "".
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.
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.
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.
Pour cette mission, vous devez soumettre votre fichier bioinfo.py au serveur de soumissions de programmes du cours. Votre fichier bioinfo.py doit au moins contenir les fonctions :
is_adn(text) positions(text,car) distance_h(text1,text2) distances_matrice(l)
Écrivez une fonction recherche ( m, v ) qui pour un nombre entier donné v, retourne True si ce nombre apparaît dans la matrice, et False si non. Par exemple, pour la matrice suivante et la valeur v=4, le résultat doit être False. Pour la valeur v=3 le résultat doit être True.
[ [ 0, 3, 2, 8 ], [ 6, 5, 2, 1 ], [ 7, 0, 3, 2 ] ]
La méthode sum(list) retourne la somme des éléments contenus dans list.
Exemple: la somme de [1,2,3] est 6
Notez que votre algorithme devrait être capable de calculer la somme même si la liste list contient des éléments malicieux (pas des nombres).
La méthode average(list) retourne la moyenne arithmétique des éléments contenu dans list, sauf si list est vide auquel cas, elle devrait retourner None.
La méthode diff_count(lst) retourne le nombre d'éléments différents contenus dans la liste lst.
Par exemple:
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 :
Et la seconde racine s'obtient via la formule suivante :
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 :
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.
Les nombres premiers (https://en.wikipedia.org/wiki/Prime_number) sont des nombres avec les caractéristiques suivantes:
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.
Vous travaillez pour une entreprise qui est active dans toute la Belgique. En tant que composant d'un système plus grand, l'entreprise a besoin d'outils qui permettent de rechercher les coordonnées des communes belges. Vous avez trouvé une liste des communes et leur coordonnées GPS en ligne et devez utiliser Python pour créer les outils demandés.
A l’issue de ce problème, chacun d’entre vous :
A l’issue de ce problème, le groupe tout entier :
La matière relative à cette mission est décrite dans les sections suivantes du syllabus en ligne :
Les questions à choix multiples de cette mission sont également accessibles en ligne depuis https://inginious.info.ucl.ac.be/course/LSINF1101-PYTHON/Session5_QCM
Dans cet exercice, nous étudions les listes de nombres entiers ordonnées de façon strictement croissante. Un exemple d'une telle liste est [-1,0,3,5]; la liste [-1,0,0,2] ne l'est pas (puisque 0 et 0 sont égales).
Étant donnée une liste de nombres entiers, comme [-2,0,3,4] ou [3,-2,0], écrivez une fonction def is_sorted(l) avec la spécification suivante:
def is_sorted ( l ): """ Retourne si la liste l est ordonnée de façon strictement croissante. Args: l: une liste de nombres entiers, positif ou négatif Retourne: Un booléen qui indique si la liste l est ordonnée de façon strictement croissante. """
Étant données deux listes ordonnées de façon strictement croissante, on veut calculer une nouvelle liste ordonnée des nombres entiers qui sont communs entre les deux listes. Par exemple, étant données les listes [-2,-1,0,1,2,3,4] et [0,1,2,5,6], on veut calculer la liste [0,1,2], qui contient les nombres entiers [0,1,2] qui sont communs entre les deux listes. Une première implémentation de cette idée est donnée ci-dessous.
def intersect ( l1, l2 ): """ Retourne une liste ordonnée des nombres entiers communs entre l1 et l2. Args: l1: une liste ordonnée de nombres entiers, positif ou négatif l2: une liste ordonnée de nombres entiers, positif ou négatif Retourne: Une liste ordonnée de nombres entiers communs entre l1 et l2. """ l = [] for e1 in range(len(l1)): for e2 in range(len(l2)): if e2 == e1: l.append ( e1 ) return l
Malheureusement, le code ne fonctionne pas encore correctement. Écrivez un test qui montre que le code n'est pas correct.
Donnée est une liste de coordonnées, comme par exemple:
coordonnees = [(0,1),(2,3),(0,1),(4,5),(1,2),(0,1),(1,1),(0,2),(1,1)]
Étudiez le code suivant:
coordonnees = [(0,1),(2,3),(0,1),(4,5)] def f ( v ): return v*v def increment ( l ): for i in range(len(l)): l[i][0] = f(l[i][0]) increment ( coordonnees ) assert coordonnees == [(0,1),(4,3),(0,1),(16,5)]
Malheureusement le code donne une erreur et ne passe pas le test. Corrigez une ligne de la fonction increment(l) de telle sorte que le code passe le test.
On représente les cours suivis par des étudiants en utilisant des listes imbriquées, comme suit:
[('LINFO1101', ['Jean', 'Pierre']), ('LINFO1110', ['Jean']),\ ('LINFO1111', ['Jean']), ('LINFO1112', ['Jacques', 'Pierre']),\ ('LINFO1113', ['Pierre'])]
Donnez un algorithme binary_search(course,list_of_courses) pour trouver tous les étudiants d'un cours donné dans cette structure de données. Copiez le code du cours et modifiez-le.
On peut appliquer l'algorithme de question 3 pour trouver les étudiants de plusieurs cours. Supposez que chaque fois que vous calculez middle, tu imprimes la valeur calculée pour middle. Dans ce cas, le nombre de valeurs imprimées pour middle correspond à la nombre de fois que la boucle while est exécutée. Combien de fois est-ce que la boucle est exécutée pour l'exemple suivant ?
La liste est:
[('LINFO1101', ['Jean', 'Pierre']), ('LINFO1110', ['Jean']),\ ('LINFO1111', ['Jean']), ('LINFO1112', ['Jacques', 'Pierre']), \ ('LINFO1113', ['Pierre'])]
Les cours donnés sont: LINFO1110, LINFO1112, LINFO1111, LINFO1114.
Pour cette mission, vous devez écrire des fonctions et tester leur bon fonctionnement. Comme dans les exercices de préparation, vous devez travailler à deux de cette façon: pendant qu'un étudiant écrit une fonction, l'autre développe la fonction de test correspondante. Lorsqu'une fonction est correctement spécifiée, on peut écrire les tests permettant de vérifier son bon fonctionnement sans connaître son code.
Dans cette mission vous allez créer plusieurs fonctions qui fonctionnent sur une liste de communes de la Belgique.
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.
Finalement, appliquez votre fonction à la liste all_communes.
É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:
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().
Écrivez une fonction tour_distance(communes, all_communes) pour calculer la distance totale d'une tournée à travers toutes les communes dans la liste communes. La tournée commence à communes[0], va ensuite vers communes[1], communes[2], ..., communes[-1], pour finalement retourner à communes[0].
De nouveau: ajoutez des spécifications pour la fonction, ainsi que des tests, dans une fonction test_tour_distance().
Pour cette mission, vous devez soumettre votre fichiers sorted_belgian_communes.py et README.txt au serveur de soumissions de programmes du cours. Les fonctions et les testes doivent être dans le même fichier. Le fichier ne doit contenir que des fonctions (en plus de la variable all_communes). Votre fichier sorted_belgian_communes.py doit au moins contenir les fonctions :
verify_order(communes) coordinate(commune,all_communes) distance(commune1, commune2, all_communes) tour_distance(communes, all_communes)
Les questions ci-dessous sont des questions supplémentaires de Question 1 de la phase de préperation; ce sont des questions à faire sur papier.
Déterminez combien de fois la ligne de code if e2 == e1: est executée pour le cas de test suivant:
assert intersect ( list(range(100)), list(range(100)) ) == list(range(100))
On va essayer de résoudre le problème plus efficacement. Une idée est de parcourir les deux listes en même temps; pour chaque élément de la première liste, on regarde si on peut trouver l'élément dans la partie de la deuxième liste qu'on n'a pas encore parcouru. Cette idée a été mise en oeuvre dans la fonction suivante:
def intersect ( l1, l2 ): """ Retourne une liste ordonnée des nombres entiers communs entre l1 et l2. Args: l1: une liste ordonnée de nombres entiers, positif ou négatif l2: une liste ordonnée de nombres entiers, positif ou négatif Retourne: Une liste ordonnée de nombres entiers communs entre l1 et l2. """ l = [] p1 = 0 p2 = 0 while p1 < len(l1): while l1[p1] > l2[p2]: p2 += 1 if l1[p1] == l2[p2]: l.append ( p2 ) p1 += 1 return l
Malheureusement, le code ne fonctionne pas encore correctement.
Écrivez quelques testes qui permettent de découvrir que le code n'est pas correct.
Donnée est une liste de coordonnées. Par exemple:
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:
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).
Donnée est une liste de coordonnées, comme dans l'exercice précédente. Nous voulons créer un dictionnaire pour identifier rapidement la valeur maximale Pour l'exemple:
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).
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.
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.
É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 :
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.
Vous allez développer un programme qui permets l’exécution de certaines tâches. Très fréquemment, un utilisateur doit faire les tâches suivantes :
Les exercices préparatoires vous permettent de completer certains éléments de cette mission.
A l’issue de ce problème, chacun d’entre vous sera en mesure d’exploiter les notions suivantes :
La matière relative à cette mission est décrite dans les sections suivantes du syllabus en ligne :
Il peut être utile de relire:
Les questions à choix multiples de cette mission sont également accessibles en ligne depuis https://inginious.info.ucl.ac.be/course/LSINF1101-PYTHON/Session6_QCM
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.
Dans les exercices suivants, vous pouvez supposer que les fichiers à lire existent et qu'il ne faut pas traiter les erreurs.
On donne des listes contenant des paires de coordonnées comme [(0.5,0.5),(0.1,0.3),(0.4,0.5)].
0.5,0.5 0.1,0.3 0.4,0.5
Considérez l'utilisation de méthodes de string telles que : * split * strip
Voyez la documentation de ces méthodes dans le manuel de référence de Python.
Dans cet exercice, les erreurs possibles lors de la lecture ou de l'écriture d'un fichier peuvent être ignorées.
Considérez le code suivant.
command = input ( "Enter your command: " ) parameters = command.split () if parameters[0] == "divide": print ( "The value of your division is: " + str ( float(parameters[1])/float(parameters[2]))) elif parameters[0] == "showfile": file = open ( parameters[1] ) print ( file.read () ) file.close () else: print ( "Command not recognized")
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.
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:
Par exemple, l'outil doit supporter cette séquence de commandes :
Welcome to your personalized tool! > file all-words.dat Loaded all-words.dat > info 11304 lines 1330218 caracters > words Read file as list of words > search presbytaerial Presbytaerial is not in the list of words > search presbyterial Presbyterial is in the list of words > exit
Si l'utilisateur spécifie un fichier autre qu'une liste de mots, ou si l'utilisateur cherche un mot sans avoir spécifié une liste de mots, l'outil doit produire un message d'erreur et continuer à fonctionner.
Le format des listes de mots est spécifié dans les exercices préparatoires. Pour éviter tout problème avec l'encodage des caractères accentués, votre liste de mots vérifiera des mots en anglais (sans accents).
Note: dans cet exercice, la liste de mots ne doit pas encore être mise en oeuvre à l'aide de dictionnaires Python, ce qui sera le sujet de la mission de la semaine prochaine.
La phase de réalisation de cette mission est moins guidée que les précédentes; vous devez choisir vous-même la subdivision de votre programme en fonctions.
Néanmoins, on vous suggère de procéder comme suit:
Pour vous aider, vous avez à disposition le fichier all-words.dat qui contient une centaine de milliers de mots de la langue anglaise ainsi que le nombre d'occurrences de ce mot. Cette liste de mots a été construit en se basant sur deux sources d'information : les mots utilisés par ispell (http://wordlist.sourceforge.net/) et la Global Service List (http://jbauman.com/gsl.html), c'est-à-dire les 2000 mots les plus fréquemment utilisés par un personne qui apprend l'anglais. Ce fichier contient les mots en minuscules et n'est pas trié dans l'ordre alphabétique. La première ligne contient le nombre de mots présents dans le fichier.
La mission de cette semaine n'aura pas de correction automatique donc soyez bien attentifs pendant la séance de feedback.
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).
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.
Écrivez un outil qui fait le suivant:
Séparez le programme en fonctions, avec au moins
Pour simplifier l'exercice, il n'est pas nécessaire de traiter les erreurs.
Écrivez une fonction table(filename_in, filename_out, width) qui crée pour un fichier donné un autre fichier dans lequel toutes les lignes ont été mises dans un tableau. Pour cet exemple:
Mons Bruxelles Ottignies Jean Charles
le résultat avec width = 8 doit être:
Mons Bruxelle Ottignie Jean Cha |
Remarquez qu'il y a un espace avant et après chaque ligne. Considérez l'utilisation des méthodes suivantes de string:
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 :
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)
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.
La matière relative à cette mission est décrite dans les sections suivantes du syllabus en ligne :
Les questions à choix multiples de cette mission sont également accessibles en ligne depuis https://inginious.info.ucl.ac.be/course/LSINF1101-PYTHON/Session7_QCM
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.
print(codes["Bruxelles"])
print(codes["Mons"])
print(codes[1000])
print(codes.get("Mons",[]))
codes["Liege"] = [4000] print(codes)
codes["Bruxelles"].append(1040) print(codes)
codes.get("Bruxelles",[]).append(1050) print(codes)
codes.get("Arlon",[]).append(8362) print(codes)
if "Bruxelles" in codes: print("Found!") else: print("Not found!")
if 1000 in codes: print("Found!") else: print("Not found!")
for x in codes: print(x)
for x in codes: print(codes[x])
for x in codes.items(): print(x)
for x, y in codes.items(): y = y + [2000] print(codes)
for x, y in codes.items(): y.append(2000) print(codes)
for x, y in codes.items(): x = x + "*" print(codes)
Considérez le code suivant:
def mot_ligne(ligne): d = {} for mot in ligne: d[mot] = 1 return d
Quelle est la taille du dictionnaire résultant des appels suivants ? Pourquoi ?
Écrivez une fonction avec la spécification suivante:
def create_index ( list_of_words ): """ crée un index pour une liste de chaînes de caractères. L'index se compose d'un dictionnaire dans lequel pour chaque chaîne de caractères dans list_of_strings on retrouve une liste des positions où l'on retrouve cette chaîne de caractères. Par exemple, pour la liste ["the","galaxy","and","the","universe","are","the","same"] Le résultat est {"the":[0,3,6],"galaxy":[1],"and":[2],"universe":[4], \ "are":[5],"same":[7]} Args: list_of_words: une liste de chaînes de caractères Retourne: un dictionnaire avec pour chaque mot dans la liste, une liste des positions de cette chaîne de caractères dans la liste """
Étant donnée:
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.)
Étant donné une structure de données comme la suivante:
É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.
Le but de cette mission est de contribuer à un outil qui permet un utilisateur de chercher répétitivement dans un fichier de texte.
Il faut implementer les fonctions suivantes dans un fichier search.py et vérifier que ces fonctions sont correctes:
La fonction readfile(filename) avec la spécification suivante:
def readfile ( filename ): """ Crée une liste des lignes contenues dans un fichier dont le nom est ``filename`` Args: filename: le nom d'un fichier de texte Retourne: une liste dans laquelle chaque ligne du fichier filename est un élément. Si filename n'existe pas, la fonction retourne une liste vide. """
La fonction get_words(line) avec la spécification suivante:
def get_words ( line ): """ pour une chaîne de caractères donnée, retourne une liste des mots dans la chaîne, en minuscules, et sans ponctuation, dans l'ordre d'apparence dans le texte. Par exemple, pour la chaîne de caractères "Turmoil has engulfed the Galactic Republic. The taxation of trade routes to outlying star systems is in dispute." Le résultat est ["turmoil", "has", "engulfed", "the", "galactic", "republic", "the", "taxation", "of", "trade", "routes", "to", "outlying", "star", "systems", "is", "in", "dispute" ] Un caractère est considéré comme une ponctuation si ce n'est pas une lettre, selon la fonction string.isalpha () . Args: line: une chaîne de caractères. Retourne: une liste des mots dans la chaîne, en minuscules, et sans ponctuation. """
Ici, vous pouvez utiliser la méthode string.isalpha(); un exemple de l'utilisation de cette méthode se trouve ci-dessous:
text = "a.b" r = "" for c in text: if c.isalpha (): r += c print(r)
La fonction create_index(filename) avec la spécification suivante:
def create_index ( filename ): """ crée un index pour le fichier avec nom ``filename``. L'index se compose d'un dictionnaire dans lequel pour chaque mot du fichier ``filename`` on retrouve une liste des indices des lignes du fichier qui contiennent ce mot. Par exemple, pour un fichier avec le contenu suivant: While the Congress of the Republic endlessly debates this alarming chain of events, the Supreme Chancellor has secretly dispatched two Jedi Knights. Une partie de l'index, representé comme dictionnaire, est: {"while": [0], "the": [0,1], "congress": [0], \ "of": [0,1], "republic": [0], ... , "jedi": [2], ...} Args: filename: une chaîne de caractères Retourne: un dictionnaire avec pour chaque mot du fichier (en minuscules) la liste des indices des lignes qui contiennent ce mot. """
Cette fonction doit utiliser les fonctions get_words et readfile.
La fonction get_lines(words,index) avec la spécification suivante:
def get_lines ( words, index ): """ Détermine les lignes qui contiennent tous les mots indexes dans ``words``, selon l'index ``index``. Par exemple, pour l'index suivant: index = {"while": [0], "the": [0,1], "congress": [0], \ "of": [0,1], "republic": [0], ... , "jedi": [2], ...} La fonction retourne get_lines(["the"]) -> [0,1] get_lines(["jedi"]) -> [2] get_lines(["the","of"],index) -> [0,1] get_lines(["while","the"],index) -> [0] get_lines(["congress","jedi"]) -> [] get_lines(["while","the","congress"]) -> [0] Args: words: une liste de mots, en minuscules index: un dictionnaire contenant pour mots (en minuscules) des listes de nombres entiers Retourne: une liste des nombres des lignes contenant tous les mots indiqués """
Commencez par faire cette fonction uniquement pour les listes avec un mot; dans ce cas, l'outil marche au moins quand l'utilisateur spécifie un seul mot. Essayez de modifier cette fonction pour les listes plus longues ensuite.
Plusieurs approches sont possible pour calculer le résultat de get_lines() pour des listes de mots plus longues. Une possibilité est de traverser la liste associé au premier mot, et de vérifier si on trouve dans ces lignes aussi les autre mots, en utilisant l'index de chaque mot.
De nouveau, les fonctions ci-dessus doivent être mises en oeuvre dans un fichier search.py.
L'outil est implementé dans un fichier utility.py, qui importe le fichier search.py. Voici le code de utility.py, que vous pouvez soumettre sans le modifier:
import search filename = input ("Spécifiez le nom de fichier: ") index = search.create_index ( filename ) while True: words = input ("Spécifiez les mots a rechercher, en utilisant des espaces entre les mots: ") lines = search.get_lines ( words.strip().split(), index ) print("Les mots se retrouvent dans ces lignes:") for line in lines: print(line)
Autrement dit, après avoir demandé le nom d'un fichier, dans une boucle, l'interface demande à l'utilisateur de donner une liste de mots; chaque fois, l'outil cherche les lignes dans lesquelles les mots spécifiés sont présents, et imprime ces lignes. Votre tâche principale est de vous assurer que l'outil fonctionne correctement, en mettant en oeuvre les fonctions dans le fichier search.py.
Pour vous aider, vous trouverez un exemple de texte episodeIV_dialogues.txt.
Créez les fonctions dans l'ordre spécifié. Si vous n'arrivez pas à terminer toutes les fonctions, soumettez les fonctions que vous avez réussi à terminer.
Pour assurer que l'outil marche correctement, vous devez ajouter des tests pour vérifier que les fonctions sont correctes; par exemple, les tests pour la fonction get_words doivent être mis dans une fonction test_get_words. Puisque vous devez tester une fonction qui lit un fichier, créez des petits fichiers pour tester cette fonction; il faut soumettre ces fichiers de texte aussi.
Les tests doivent être mis dans un fichier test.py qui importe search.py. Un petit exemple du contenu du fichier test.py est:
import search def test_get_words (): assert search.get_words ( "Turmoil has engulfed the Galactic Republic." ) == ["turmoil", "has", "engulfed", "the", "galactic", "republic"], "Petit exemple donné" test_get_words ()
Si vous le souhaitez, vous pouvez étendre l'outil même, par exemple, pour montrer les lignes au lieu des nombres des lignes. Dans ce cas vous pouvez modifier le code du fichier utility.py. Indiquez ceci dans le commentaire de utility.py.
Pour cette mission, vous devez soumettre:
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 :
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:
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:
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.
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.
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.
A l'issue de cette mission, chacun d'entre vous :
La matière relative à cette mission est décrite dans les sections suivantes de la partie Objects du syllabus en ligne:
Un exemple d'un un premier programme utilisant des objets en Python, utlisé comme illustration dans le cours théorique, se trouve dans l'annexe suivant:
Les questions à choix multiples de cette mission sont accessibles en ligne depuis https://inginious.info.ucl.ac.be/course/LSINF1101-PYTHON/Session9_QCM
Considérez le code suivant d'une classe Student représentant un étudiant:
class Student : def __init__(self,n) : """ Initialise un nouvel objet de type Student avec un nom n donné. @pre: - @post: Un objet de type Student a été créé avec comme 'name' n, et un score None pour chacun des trois tests 'test1', 'test2' et 'test3' """ # nom de l'étudiant self.name = n # score reçu par l'étudiant sur trois tests # (initialement None car l'étudiant n'a pas encore passé les tests) self.test1 = None self.test2 = None self.test3 = None def average_score(self) : """" Calcul de la moyenne des scores obtenus par l'étudiant sur les 3 tests. @pre: les variables d'instance test1, test2 et test3 contiennent des valeurs de type int @post: retourne la moyenne de ces trois valeurs """ return (self.test1 + self.test2 + self.test3) / 3
Les instructions suivant donnent un exemple de comment cette classe peut être utilisé:
student = Student("Kim") student.test1 = 14.0 student.test2 = 10.5 student.test3 = 12.0 print("Bonjour, " + student.name + ". Vos scores sont:") print(student.test1) print(student.test2) print(student.test3) print("La moyenne de vos scores est " + str(student.average_score())) student2 = student print("La moyenne de vos scores est " + str(student2.average_score())) student = None student2 = None
Sur base de ces extraits, donnez des exemples des notions suivantes, en veillant à être précis et rigoureux dans votre formulation:
**Classe, objet (ou instance)**
**Constructeur et méthode d'initialisation**
**Attribut (ou variable d'instance)**
**Méthode d'instance**
**Référence à un objet et la valeur None**
**Référence à self**
Dans la question précédente, expliquez les notations student.name, student.average_score() et self.name et leur interprétation par Python.
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
Dans le cadre d'un cours de programmation, un étudiant a développé une classe Pair permettant de manipuler un objet contenant une paire d'entiers. Le code de cette classe Python est repris ci-dessous :
class Pair: """ Une paire d'entiers """ def __init__(self, x=None, y=None): """ @pre - @post crée une paire (a,b) composée de x et y, ou une paire non-initialisée si aucune valeur de x et de y n'est donné lors de l'appel au constructeur """ self.a = x # le premier élément de la paire self.b = y # le second élément de la paire def __str__(self): return str(self.a) + ", " + str(self.b)
Remarque: La notation x=None, y=None dans l'entête de la méthode __init__ permet de donner des valeurs par défaut à certains ou à tous paramètres de la fonction. Lorsque nous appelons la fonction, si des valeurs ne sont pas données pour ces paramètres, ils reçoivent les valeurs par défaut sinon, on peut leur donner une valeur différente en donnant un argument lors de l'appel.
Considérons maintenant le code Python ci-dessous illustrant une utilisation de la classe Pair:
p0 = Pair() ##1## p1 = Pair(0,0) ##2## p2 = Pair(1,1) ##3## p0.b = 3 ##4## p1.a = 10 ##5## p2.a = p1.a ##6## p2 = p1 ##7##
Expliquez les opérations effectuées par chacune de ces lignes. Pensez à utiliser une représentation graphique des différents objets telle que celle utilisée dans le syllabus ou les transparents en indiquant les valeurs des différentes variables d'instance.
Après avoir exécuté les opérations précédentes, qu'impriment les instructions suivantes?
print(p0) ##8## print(p1) ##9## print(p2) ##10##
Considérez les instructions suivantes qui utilisent la classe Pair vue précédemment:
p1 = Pair(9, 42) p2 = Pair(9, 42); if (p1 == p2) : print("Egaux en 1") ##1## p2 = p1 if (p1 == p2) : print("Egaux en 2") ##2##
Lesquelles des lignes ##1## et/ou ##2## produiront-elles un message? Pourquoi? Expliquez ce comportement avec un dessin.
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.
L'objectif principal de cette mission est de définir et d'utiliser trois classes correspondant respectivement à une durée (une espace de temps sous la forme heures-minutes-secondes), à une chanson (caractérisée par un titre, un auteur et une durée) et à un album (un ensemble de chansons). Vous utiliserez ensuite ces classes pour réaliser la génération d'albums souhaitée. Vous travaillerez par groupes de deux.
Dans le cadre du prototype à réaliser, les chansons vous sont fournies dans un fichier contenant des lignes de texte:
"TITRE AUTEUR MIN SEC"
où "TITRE", "AUTEUR", "MIN" et "SEC" correspondent respectivement au titre, à l'auteur, et à la durée de la chanson en minutes et secondes, et ne contiennent eux-mêmes pas d'espaces, par exemple:
Let's_Dance David_Bowie 4 5 Relax Frankie_Goes_To_Hollywood 3 54 Purple_Rain Prince 5 48 Enjoy_The_Silence Depeche_Mode 4 13
Ce format facilite leur lecture. On vous rappelle que la méthode split() permet de séparer un string contenant des espaces en mots individuels.
Il est plus que jamais important de bien tester votre code, étant donné que les classes que vous définissez pourront être utilisées dans des usages multiples. Au sein de votre binôme, pendant qu'un étudiant se concentre sur le développement d'une classe, l'autre pourrait préparer les tests pour cette classe. Les spécifications des méthodes étant donné par avance, il est en effet tout à fait possible de préparer des tests en même temps que (voire avant) la classe à tester. Il s'agit en quelque sorte d'un jeu: le développeur parviendra-t-il à écrire une classe qui fonctionnera correctement sous toutes les attaques du testeur? Le testeur parviendra-t-il à trouver le test qui causera un fonctionnement incorrect?
Remarque: Lors de cette mission vous utiliserez encore les instructions 'assert' pour tester votre programme orienté objet. Dans une mission futur nous introduirons le mécanisme des 'tests unitaires' qui sera encore mieux approprié pour tester du code orienté objets.
Chargez les fichiers "music-db.txt", "mission8.py" et "test.py".
Commencez par définir la classe Duree qui représente une durée exprimée en heures (h), minutes (m) et secondes (s).
Ajoutez d'abord la méthode d'initialisation __init__(self, h, m, s), qui requiert que m et s soient dans l'intervalle [0..60[ et crée un nouveau temps de h heures, m minutes et s secondes. Ajoutez une spécification à cette méthode et vérifiez que les conditions requises soient bien respectées.
def __init__(self,h,m,s): """ @pre: h, m et s sont des entiers positifs (ou zéro) m et s sont < 60 @post: Crée une nouvelle durée en heures, minutes et secondes. """
Ajoutez ensuite les méthodes correspondant aux spécifications suivantes:
def to_secondes(self): """ @pre: - @post: Retourne le nombre total de secondes de cette instance de Duree (self). Par exemple, une durée de 8h 41m 25s compte 31285 secondes. """ def delta(self,d) : """ @pre: d est une instance de la classe Duree @post: Retourne la différence en secondes entre cette durée (self) et la durée d passée en paramètre. Cette valeur renovoyée est positif si cette durée (self) est plus grand que la durée d, négatif sinon. Par exemple, si cette durée (self) est 8h 41m 25s (donc 31285 secondes) et la durée d est 0h 1m 25s, la valeur retournée est 31200. Inversement, si cette durée (self) est 0h 1m 25s et la durée d est 8h 41m 25s, alors la valeur retournée est -31200. """ def apres(self,d): """ @pre: d est une instance de la classe Duree @post: Retourne True si cette durée (self) est plus grand que la durée d passée en paramètre; retourne False sinon. """ def ajouter(self,d): """ @pre: d est une instance de la classe Duree @post: Ajoute une autre durée d à cette durée (self), corrigée de manière à ce que les minutes et les secondes soient dans l'intervalle [0..60[, en reportant au besoin les valeurs hors limites sur les unités supérieures (60 secondes = 1 minute, 60 minutes = 1 heure). Ne retourne pas une nouvelle durée mais modifié la durée self. """ def __str__(self): """ @pre: - @post: Retourne cette durée sous la forme de texte "heures:minutes:secondes". Astuce: l'expression "{:02}:{:02}:{:02}".format(heures, minutes, secondes) retourne le string désiré avec les nombres en deux chiffres en ajoutant les zéros nécessaires. """
Dans le fichier test.py, ajoutez ou complétez au fur et à mesure des fonctions tests pour tester la classe Duree. Exécutez ces tests régulièrement et assurez-vous que les résultats sont conformes aux spécifications, en corrigeant au besoin.
Il est une bonne idée d'avoir un ou plusieurs tests, avec différents scénarios de test, par méthode de la classe Duree. Par exemple, pour la méthode ajouter() de votre classe Duree, vous pourrez implémenter une fonction test_Duree_ajouter() pour tester les différents scénarios d'utilisation de la méthode ajouter() de cette classe. Vous pouvez vous inspirer des quelques tests qui se trouvent déjà dans le fichier test.py.
Définissez maintenant la classe Chanson représentant une chanson, caractérisée par un titre t (string), un auteur a (string) et une durée d (Duree). Implémentez la méthode d'initialisation __init__ ainsi que la méthode de conversion __str__ correspondant aux spécifications suivantes:
def __init__(self,t,a,d): """ @pre: t et a sont des string, d est une instance de la classe Duree @post: Crée une nouvelle chanson, caractérisée par un titre t, un auteur a et une durée d. """ def __str__(self): """ @pre: - @post: Retourne un string décrivant cette chanson sous le format "TITRE - AUTEUR - DUREE". Par exemple: "Let's_Dance - David_Bowie - 00:04:05" """
Ajoutez au fichier test.py une série de tests pour tester les différentes méthodes de la classe Chanson.
Définissez maintenant la classe Album représentant un album contenant une ou plusieurs chansons.
Implémentez d'abord la méthode d'initialisation __init__ pour créer un album vide:
def __init__(self, numero): """ @pre: numero est un entier identifiant de facon unique cet album @post: Crée un nouvel album, avec comme identifiant le numero, et avec une liste de chansons vide. """
Implémentez également une méthode add(self,chanson) pour ajouter une chanson à un album. Cette méthode retourne False et ne modifie rien si lors de l'ajout de la chanson l'album aurait atteint 100 chansons ou sa durée aurait dépassé 75 minutes. Sinon la chanson est rajoutée à la fin de la liste des chansons de cet album, la durée totale de l'album est augmentée avec la durée de la chanson, et la méthode add retourne True.
Finalement, implémentez la méthode de conversion __str__ pour imprimer la description d'un album selon le format suivant:
Album 21 (12 chansons, 00:47:11) 01: White_Wedding - Billy_Idol - 00:04:12 02: Stand_And_Deliver - Adam_&_The_Ants - 00:03:33 03: You_Spin_Me_Around - Dead_Or_Alive - 00:03:14 04: Wired_For_Sound - Cliff_Richard - 00:03:38 05: Some_Like_It_Hot - The_Power_Station - 00:03:45 06: 99_Luftballons - Nena - 00:03:50 07: Keep_On_Loving_You - Reo_Speedwagon - 00:03:22 08: Seven_Into_The_Sea - In_Tua_Nua - 00:03:51 09: Love_Is_A_Battlefield - Pat_Benatar - 00:05:20 10: Etienne - Guesch_Patti - 00:04:07 11: This_Is_Not_A_Love_Song - Public_Image_Limited - 00:04:12 12: Love_Missile_F1-11 - Sigue_Sigue_Sputnik - 00:04:07
Ajoutez au fichier test.py une série de tests pour tester la classe Album.
Finalement, complétez votre programme par une série d'instructions qui:
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
Complétez le fichier test.py avec quelques tests pour démontrer que vos 3 classes Duree, Chanson et Album collaborent correctement et peuvent être utilisés pour créer des albums de chansons.
Le diagramme de classes suivant résume les différentes classes et méthodes à implémenter lors de cette mission :
Pour cette mission, vous devez soumettre votre programme mission8.py, le fichier test.py avec vos fonctions de tests pour les différentes classes que vous avez implémenté et votre fichier README.txt au serveur de soumissions de programmes du cours.
Votre fichier mission8.py doit contenir une définition des classes Duree, Chanson et Album, ainsi qu'une série d'instructions pour lire le fichier et créer et imprimer les albums.
Votre fichier test.py doit au moins contenir des tests pour les différentes méthodes des classes Duree, Chanson et Album, ainsi qu'une série d'instructions pour lancer tous les tests.
L'exécution de votre programme mission8.py doit imprimer l'output ci-dessus sur base du fichier original music-db.txt. Il ne vous est pas permis de faire des modifications à ce fichier.
Créer une classe Personne décrivant des personnes physiques ayant un nom (un string), un attribut booléen 'desire_enfant' et une liste d'enfants (d'autres instances de la même classe) et comme méthodes:
Utilisez et testez cette classe pour créer une grande famille de personnes.
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.
PCLine s.p.r.l., une société de vente de matériel et de service informatique locale de Louvain-la-Neuve, fait appel à vos services pour développer ses applications informatisées de facturation. Les gérants de PCLine disposent déjà d'un programme pour imprimer leurs factures et calculer la TVA et les totaux. Ils désirent développer également la livraison des articles et de pièces, en intégrant l'impression des bordereaux de livraison dans leur logiciel de facturation existant, sans devoir écrire complètement leur logiciel existant. Heureusement, leur logiciel étant écrit en Python dans un style orienté objets, leur consultant de l'UCLouvain leur a confirmé qu'il était possible de l'étendre sans le modifier au moyen des mécanismes d'héritage de Python. Ils ont donc confié aux étudiants de 1er Bac la tâche d'ébaucher la représentation des pièces en catalogue, leur intégration dans la facturation, ainsi que l'impression des bordereaux de livraison en plus de l'impression des factures.
A l'issue de cette mission, chacun d'entre vous :
pourra masquer les variables d'instance d'une classe et écrire des méthodes pour y accéder;
aura appris la notion de variable de classe et son utilité;
pourra expliquer en ses propre mots et illustrer par l'exemple les principes de l'héritage en Python:
* l'héritage d'une classe; * la redéfinition de méthodes; * l'utilisation de ``self`` et ``super()``;
sera capable d'utiliser l'héritage pour étendre un programme Python;
pourra utiliser les méthodes magiques comme
* ``__init__`` pour initialiser les objets d'une classe; * ``__str__`` pour retourner une représentation textuelle d'un instance d'une classe; * ``__eq__`` pour définir l'égalité entres objets d'une classe.
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:
Les questions à choix multiples de cette mission sont accessibles en ligne depuis https://inginious.info.ucl.ac.be/course/LSINF1101-PYTHON/Session10_QCM
Considérez une classe Pair :
class Pair: def __init__(self, x, y): self.a = x self.b = y def __str__(self): return str(self.a) + ", " + str(self.b)
Maintenant considérez le code suivant :
p1 = Pair(9, 42) p2 = Pair(9, 42); print(p1 == p2)
La dernière instruction affichera False. (Pourquoi?)
Ajoutez une méthode __eq__(self, p) à la classe Pair qui compare la valeur de deux paires, de manière à ce que print(p1 == p2) imprimera True au lieu de False.
Dans l'implémentation de votre méthode pensez également à gérer le cas où p == None.
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 :
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()
class E : def m(self) : print("E 1") def n(self) : print("E 2") def p(self) : self.n() # appel à la méthode n sur la même instance class F(E) : def q(self) : print("F 1") def n(self) : super().n() # appeler la méthode définie sur la classe mère print("F 2") def r(self) : self.m() # appel à la méthode m sur la même instance
Expliquer ce qui sera affiché lors de l'exécution des instructions Python suivantes :
f = F() f.q() f.m() f.r() f.n() f.p()
Considérons la classe Figure reprise ci-dessous :
class Figure: def __init__(self,x,y,visible=False) : """ @pre x, y sont des entiers représentant des positions sur l'écran @post Une figure a été créée avec centre de gravité aux coordonnées x,y. Cette figure n'est initialement pas visible. """ self.x = x self.y = y self.__visible = visible def est_visible(self) : """ @pre - @post a retourné la visibilité de cette figure """ return self.__visible def surface(self) : """ @pre - @post la surface (un float) de la figure a été calculé et retournée """ pass # code non fourni
Cette classe Figure est la classe mère d'un ensemble de classes permettant de représenter des figures géométriques. Chaque figure géométrique est placée à une position (x,y) (centre de gravité) sur l'écran et la classe contient des variables d'instance et des méthodes permettant de manipuler cette figure géométrique (notamment des méthodes permettant d'afficher la figure à l'écran, mais ces méthodes ne sont pas reprises dans les extraits présentés dans cet exercice). Parmi ces figures géométriques, on trouve notamment la classe Rectangle qui hérite de la classe Figure et dont un fragment est repris ci-dessous :
class Rectangle(Figure): def __init__(self,longueur,largeur,x,y) : """ @pre longueur et largeur sont des entiers positifs x, y sont des entiers représentant des positions sur l'écran @post un rectangle dont le centre de gravite est en x,y et ayant comme longueur lo et comme largeur la a été créé """ super().__init__(x,y) self.longueur = longueur self.largeur = largeur def __str__(self) : return str((self.longueur,self.largeur,self.x,self.y,self.est_visible())) >>> r = Rectangle(10,20,0,0) >>> print(r) (10, 20, 0, 0, False)
Maintenant expliquez :
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 ):
Comment feriez-vous maintenant pour définir une classe Carre qui étend la classe Rectangle et permet de représenter un carré ?
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)
Et voici finalement une dernière question pour illustrer l'utilisation d'une variable de classe.
Complétez la classe Ticket ci-dessous:
""" Un ticket de parking """ class Ticket : __prochain_numero = 1 # variable de classe pour générer le numéro du ticket def __init__(self) : """ @pre - @post Crée un ticket avec un nouveau numéro. Les numéros sont attribués séquentiellement à partir de 1. """ # A COMPLETER def numero(self): """ @pre - @post retourne le numero de billet """ return self.__numero
Pour cette mission, vous disposez au départ d'un programme simple mission9.py permettant d'imprimer des factures. Ce programme comporte principalement deux classes:
Un fichier de test initiale test.py est également fournie. Exécuter ce fichier test produira l'exemple de facture suivant:
Facture PC Store - 22 novembre =================================================================================== | Description | prix HTVA | TVA | prix TVAC | =================================================================================== | laptop 15" 8GB RAM | 743.79 | 156.20 | 899.99 | | installation windows | 66.11 | 13.88 | 79.99 | | installation wifi | 45.22 | 9.50 | 54.72 | | carte graphique | 119.49 | 25.09 | 144.58 | =================================================================================== | T O T A L | 974.61 | 204.67 | 1179.28 | ===================================================================================
Partant de ce code déjà fonctionnel, l'objectif principal de cette mission est de développer des classes qui héritent de la classe Article , en offrant des fonctionnalités supplémentaires tout en restant utilisables par la classe Facture . Dans un deuxième temps, vous ajouterez aussi une méthode à la classe Facture qui exploite ces nouvelles fonctionnalités.
Votre programme final devrait être capable de calculer et générer des factures plus complets comme
Facture No 1 : Facture PC Store - 22 novembre =================================================================================== | Description | prix HTVA | TVA | prix TVAC | =================================================================================== | laptop 15" 8GB RAM | 743.79 | 156.20 | 899.99 | | installation windows | 66.11 | 13.88 | 79.99 | | installation wifi | 45.22 | 9.50 | 54.72 | | carte graphique | 119.49 | 25.09 | 144.58 | | Réparation (0.75 heures) | 46.25 | 9.71 | 55.96 | | 1 * disque dur 350 GB @ 49.99 | 49.99 | 10.50 | 60.49 | | 3 * souris bluetooth @ 15.99 | 47.97 | 10.07 | 58.04 | | 5 * adaptateur DVI - VGA @ 12.00 | 60.00 | 12.60 | 72.60 | | 2 * Java in a Nutshell @ 24.00 | 48.00 | 2.88 | 50.88 | | 5 * souris bluetooth @ 15.99 | 79.95 | 16.79 | 96.74 | =================================================================================== | T O T A L | 1306.77 | 267.22 | 1573.99 | ===================================================================================
et des bordereaux de livraison tels que celui-ci
Livraison - Facture No 1 : PC Store - 22 novembre =================================================================================== | Description | poids/pce | nombre | poids | =================================================================================== | disque dur 350 GB @ 49.99 (!) | 0.355kg | 1 | 0.355kg | | souris bluetooth @ 15.99 | 0.176kg | 3 | 0.528kg | | adaptateur DVI - VGA @ 12.00 | 0.000kg | 5 | 0.000kg | | Java in a Nutshell @ 24.00 | 0.321kg | 2 | 0.642kg | | souris bluetooth @ 15.99 | 0.176kg | 5 | 0.880kg | =================================================================================== | 5 articles | | 16 | 2.405kg | =================================================================================== (!) *** livraison fragile ***
Voici les étapes à suivre.
Chargez les fichiers mission9.py et test.py et étudiez leurs contenus. Vous disposez des classes et fonctions suivants:
Vous devrez vous-mêmes créer au moins deux classes ArticleReparation et ArticlePiece qui héritent de la classe Article, une classe Piece (utilisée par la classe ArticlePiece), ainsi que deux méthodes supplémentaires dans Facture , selon les instructions qui suivent.
Au fichier mission9.py , ajoutez une nouvelle classe ArticleReparation qui hérite de la classe Article . Cette nouvelle classe représente une prestation de réparation de durée donnée (un float, en heures).
Définissez une méthode d'initialisation avec la durée en paramètre.
Re-définissez la méthode description() pour fournir un descriptif adéquat comme Reparation (0.75 heures).
Re-définissez la méthode prix() pour calculer un coût fixe de 20 euro plus un coût variable de 35 euro/h. Pour une réparation de 0.75 heures ça donne donc un coût de 20 + 35*0.75 = 46.25 euro HTVA.
Dans le fichier test.py , ajoutez des tests pour tester cette nouvelle classe et son utilisation dans une facture. Par exemple, vérifiez que la ligne correspondant à une réparation soit affiché comme:
Facture PC Store - 22 novembre =================================================================================== | Description | prix HTVA | TVA | prix TVAC | =================================================================================== | ... | | Réparation (0.75 heures) | 46.25 | 9.71 | 55.96 | =================================================================================== | T O T A L | 1020.86 | 214.38 | 1235.24 | ===================================================================================
Créez une nouvelle classe ArticlePiece qui hérite de Article et qui représente l'achat pas d'un seul article mais d'un nombre donné d'une pièce donnée. (Par exemple, 3 souris Bluetooth à 15.99 EUR par pièce.)
Implémentez d'abord une nouvelle classe Piece qui représente la pièce dont on veut facturer plusieurs exemplaires. Elle comporte les données suivantes:
- une description (string), p.ex. 'souris bluetooth'; - un prix unitaire (float), p.ex. 15.99 Euro;
et, optionnellement
- un poids unitaire en kg (float), p.ex. 0,154 kg; - un indicateur booléen indiquant si la pièce est fragile, p.ex. un disque dur est fragile mais pas une souris; - un indicateur booléen indiquant si la pièce est à taux de TVA réduit, p.ex. les livres bénéficient de TVA réduite.
Ensuite implémentez la classe ArticlePiece qui hérite de Article
Finalement, dans le fichier test.py , ajoutez des tests pour tester ces nouvelles classes et leur utilisation dans une facture. Par exemple, vérifiez que les lignes correspondant aux articles pièces soient affichés comme:
Facture PC Store - 22 novembre =================================================================================== | Description | prix HTVA | TVA | prix TVAC | =================================================================================== | ... | | 3 * souris bluetooth @ 15.99 | 47.97 | 10.07 | 58.04 | | 2 * Java in a Nutshell @ 24.00 | 48.00 | 2.88 | 50.88 | | ... | =================================================================================== | T O T A L | 1306.77 | 267.22 | 1573.99 | ===================================================================================
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 d'une Piece pce dans la facture, en totalisant sur tous les articles qui concernent cette pièce. (Vous pouvez utiliser le fait que le comparateur ``==`` a été redéfinie dans la classe ``Piece`` (via la méthode magique ``__eq__`` que vous avez ajoutée).)
Dans la classe Facture, ajoutez une méthode print_livraison() qui imprime un bordereau de livraison comme
Livraison - Facture No 1 : PC store 22 octobre =================================================================================== | Description | poids/pce | nombre | poids | =================================================================================== | disque dur 350 GB (!) | 0.355kg | 1 | 0.355kg | | souris bluetooth | 0.176kg | 3 | 0.528kg | | adaptateur DVI - VGA | 0.000kg | 5 | 0.000kg | | Java in a Nutshell | 0.321kg | 2 | 0.642kg | | souris bluetooth | 0.176kg | 5 | 0.880kg | =================================================================================== | 5 articles | | 16 | 2.405kg | =================================================================================== (!) *** livraison fragile ***
Ce bordereau:
Remarquez que les détails imprimés dans ce bordereau de livraison ne concernent que les articles de type ArticlePiece; les autres articles sont ignorés. Pour faciliter le formatage du texte, vous pouvez utiliser la méthode format, déjà utilisée à plusieurs endroits dans la classe Facture. Si vous ne la connaissez pas, n'hésitez pas à chercher en-ligne comment cette méthode format fonctionne exactement. Pour implémenter la méthode print_livraison() , réutiliser un maximum de méthodes déjà existantes de la classe Facture .
Finalement, modifiez le fichier test.py pour tester votre nouvelle méthode. En particulier, vérifiez qu'un bordereau de livraison soit affiché comme:
Livraison - Facture No 1 : PC Store - 22 novembre =================================================================================== | Description | poids/pce | nombre | poids | =================================================================================== | disque dur 350 GB @ 49.99 (!) | 0.355kg | 1 | 0.355kg | | souris bluetooth @ 15.99 | 0.176kg | 3 | 0.528kg | | adaptateur DVI - VGA @ 12.00 | 0.000kg | 5 | 0.000kg | | Java in a Nutshell @ 24.00 | 0.321kg | 2 | 0.642kg | | souris bluetooth @ 15.99 | 0.176kg | 5 | 0.880kg | =================================================================================== | 5 articles | | 16 | 2.405kg | =================================================================================== (!) *** livraison fragile ***
Le diagramme de classes suivant résume les différentes classes et méthodes à implémenter lors de cette mission :
Pour cette mission, vous devez soumettre toutes les classes de votre programme dans un seul fichier mission9.py, vos classes tests dans un fichier test.py, ainsi que votre fichier README.txt qui décrit comment on peut tester votre code.
Votre fichier mission9.py doit contenir les classes Facture, Article, ArticleReparation, ArticlePiece et Piece.
Votre fichier test.py doit contenir des tests pour chacune des classes et étappes de cette mission, ainsi qu'une série d'instructions à la fin pour lancer tous les tests automatiquement lors de l'exécution du fichier.
L'exécution de votre programme mission9.py doit imprimer une facture et un bon de livraison comme illustré plus haut dans ce document.
Il est possible d'ajouter de multiples variantes d'article à ce programme. Par exemple:
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() .
Quelqu'un a programmé une classe Compte représentant un compte bancaire avec 2 attributs privés __titulaire (représentant le titulaire du compte) et __solde (représentant le montant sur le compte, initialement zéro) et 1 attribut publique représentant la banque du compte.
class Compte : def __init__(self, banque, titulaire, solde = 0) : self.banque = banque self.__titulaire = titulaire self.__solde = solde def banque(self) : return self.banque def titulaire(self): return self.__titulaire def solde(self): return self.__solde def __str__(self) : return "Banque: " + self.banque() \ + " Compte: " + self.titulaire() \ + " Solde: " + str(self.solde()) a = Compte("ShittyBank","Kim") print(a)
Malheureusement, quand on exécute l'instruction print(a), une erreur se produit:
Traceback (most recent call last): > print(a) > print(self.banque()) > TypeError: 'str' object is not callable
Quel est le problème? Pouvez-vous corriger le code?
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 :
Vous apprendrez également à écrire des tests unitaires pour vos programmes orientés objets.
Si vous n'avez pas encore eu le temps de relire en détail les différents chapitres de la partie Objects du syllabus en ligne, maintenant est venu le moment de rattraper votre retard. Le syllabus explique bien différents concepts, sur un autre exemple que les exemples utilisés dans le cours magistral :
On vous conseille également de tester et de jouer avec les différents exemples de code qui se trouvent dans les annexes suivantes, venant soit du syllabus en ligne soit correspondant aux exemples du cours magistral :
Dans cette mission, vous devrez également utiliser le framework unittest pour produire des classes de test. En préparation de cette mission, consultez donc la documentation de ce cadre de test, et essayez de faire quelques classes test simple en utilisant cet approche. Un bon tutoriel couvrant, entre autres, les tests unitaires avec unittest se trouve ici .
Les questions à choix multiples de cette mission sont accessibles en ligne depuis https://inginious.info.ucl.ac.be/course/LSINF1101-PYTHON/Session10_2019_QCM
On vous donne le code suivant qui teste certaines fonctionnalités du module random.
import unittest import random class RandomTest(unittest.TestCase): """Classe de tests utilisée pour tester les fonctions du module 'random'""" def setUp(self): """Initialisation des tests.""" self.l = list(range(10)) def test_choice(self): """Test de fonctionnement de la fonction random.choice""" e = random.choice(self.l) # Vérifie que 'e' est dans 'l' self.assertIn(e,self.l) def test_shuffle(self): """Test le fonctionnement de la fonction random.shuffle""" random.shuffle(self.l) self.l.sort() self.assertEqual(self.l, list(range(10))) def test_sample(self): """Test le fonctionnement de la fonction random.sample""" extrait = random.sample(self.l, 5) for element in extrait: self.assertIn(element,self.l) self.assertRaises(ValueError, random.sample, self.l, 20) # Pour lancer automatique ces tests quand on exécute ce fichier if __name__ == '__main__': unittest.main()
Considérant cette classe, on vous demande de :
Expliquez cet extrait de code
if __name__ == '__main__': unittest.main()
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()
Que donnent-vos tests unitaires pour les implémentations suivantes :
def carre_parfait (x) : return True
def carre_parfait (x) : return False
def carre_parfait (x) : cur = 0 while not cur*cur == x : cur += 1 return True
import math def carre_parfait (x) : root = math.sqrt(x) return root.is_integer()
import math def carre_parfait (x) : if x < 0 : return False root = math.sqrt(x) return root.is_integer()
L'objectif de cette mission est de créer des robots virtuels maintenant un état représentant leur position à l'écran et des opérations permettant de les faire bouger sur l'écran. On peut se baser sur plusieurs bibliothèques graphiques pour implémenter de tels robots. Cette mission vise à illustrer que, grace au polymorphisme, il devient relativement facile de remplacer une telle bibliothèque par une autre sans devoir modifier beaucoup de code.
On vous fournira une première implémentation basé sur la bibliothèque graphics.py de Python. A vous de proposer une implémentation alternative en utilisant la bibliothèque turtle. Ces deux types de robots sont polymorphe: ils comprennent exactement les mêmes messages, mais l'un est implémenté avec des positions absolues sur un plan XY, tandis que l'autre utilise des positions relatives.
Ensuite on vous demandera d'étendre davantage la fonctionnalité de ces robots, ce qui vous permettra de découvrir la puissance du concept de l'héritage pour la réutilisation du code.
Il sera aussi important de bien tester à la fois les classes qui vous sont fournies et que vous implémenterez, avec des tests unitaires. C'est-à-dire que vous créerez, par classe à tester, une classe test correspondante, avec des méthodes tests pour chacune des méthodes de la classe à tester. Ceci vous permet de tester, à une granularité fine, les différents unités (les classes et les méthodes) de votre code orienté objet.
Les différents concepts traités dans cette mission seront, entre autres : le polymorphisme, la composition, la délégation, l'héritage, la duplication et la réutilisation de code, la substitutabilité, l'utilisation de self et de super(), et les tests unitaires. Vous travaillerez par groupes de deux.
Avant de commencer, installez le package graphics.py permettant de dessiner des figures simples dans une fenêtre graphique. Ce package sera utilisée par la classe XYRobot. Vous pouvez installer ce package facilement depuis Thonny en suivant les étapes suivantes: (1) Sélectionner le menu Tools > Manage Packages... en Thonny; (2) taper graphics.py dans le champs de recherche pour retrouver le bon package et appuyez sur Install . (On a besoin du package graphics.py développé par John Zelles pour utilisation avec son livre Python Programming: An Introduction to Computer Science. La documentation pour ce package se trouve ici .)
La classe XYRobot vous est fournie dans le fichier XYRobot.py sur le site inginious où vous pouvez remettre votre solution. Analysez le code de cette classe attentivement. Elle :
Utilise le package graphics.py que vous avez installé dans l'étape prédédente.
Utilise des fonctions goniométriques comme cos et sin ainsi que la constante mathématique pi, fournies par le module math.
Représente un robot virtuel ayant un nom, une position (x, y), et une direction (angle). Quand il bouge, ce robot dessine ses mouvements dans une fenêtre représentant un plan XY.
En plus des méthodes habituelles __init__ et __str__ ainsi que des méthodes accesseurs et mutateurs, cette classe implémente des méthodes comme:
- move_forward(distance) : fait avancer le robot de distance pixels et trace une ligne lors de ce mouvement
- move_backward(distance) : fait reculer le robot de distance pixels et trace une ligne lors de ce mouvement
- turn_left() : fait tourner le robot de 90 degrés vers la gauche (dans le sens contraire des aiguilles d'une montre)
- turn_right() : fait tourner le robot de 90 degrés vers la droite (dans le sens des aiguilles d'une montre)
Appeler ces méthodes fait bouger le robot et dessine des figures sur un plan XY. Il suffit d'exécuter le code fourni dans le fichier pour avoir un exemple concret. N'oubliez pas d'installer la bibliothèque graphics.py avant d'exécuter ce fichier.
Tandis que l'implémentation de la classe XYRobot vous est fournie, il manque une classe avec des tests unitaires afin de vérifier que le robot bouge et met à jour ses attributs correctement. L'objectif de cette étape sera donc de créer une classe test avec des tests unitaires pour la classe qui vous est fournie.
Implémentez cette classe de test TestXYRobot afin de vérifier le comportement correct des différentes méthodes de la classe XYRobot. Pour réaliser vos tests, il est important à savoir que le package ``graphics.py`` considère que le point avec position (x=0,y=0) se trouve dans le coin supérieur gauche de la fenêtre.
Par exemple, quand on crée un nouveau robot r2d2 = XYRobot("R2-D2") il se trouvera à la position (x=0,y=0) avec comme angle 0 (direction Est). Après avoir exécuté r2d2.move_forward(50) le robot devrait se trouver à la position (x=50, y=0), approximativement, à cause des arrondis dans les calculs. Ensuite, après avoir exécuté r2d2.turn_right() l'angle du robot sera 90° (approximativement), etc.
Soyez le plus complet possible dans vos tests. Mettez votre classe test TestXYRobot dans un fichier séparé TestXYRobot.py qui s'occupera de charger le fichier XYRobot.py et d'exécuter les différents tests sur la classe XYRobot.
Maintenant c'est à vous d'implémenter une classe TurtleBot qui est polymorphe avec la clase XYRobot de l'étape précédente. C'est-à-dire que, en plus des méthodes __init__ et __str__ et des méthodes accesseurs (dont angle() et position()) et mutateurs, elle doit implémenter les mêmes méthodes :
- move_forward(distance) : fait avancer le robot de distance pixels et trace une ligne lors de ce mouvement
- move_backward(distance) : fait reculer le robot de distance pixels et trace une ligne lors de ce mouvement
- turn_left() : fait tourner le robot de 90 degrés vers la gauche (dans le sens contraire des aiguilles d'une montre)
- turn_right() : fait tourner le robot de 90 degrés vers la droite (dans le sens des aiguilles d'une montre)
La différence majeure est que la classe TurtleBot fait ces dessins via un objet de type Turtle. Cette classe sera donc assez facile à implémenter en utilisant un objet de type Turtle comme attribut. Le travail d'avancer, tourner et dessiner pourra alors être délégué à cette tortue. Pour rappel, la classe Turtle du package turtle.py fournit des méthodes comme position, heading, forward, backward, right et left. (Voici la documentation pour ce package.)
Pour implémenter la classe ``TurtleBot`` et effectuer vos tests, il est important à savoir que dans la fenêtre graphique du turtle, la position (x=0,y=0) se trouve au milieu de la fenêtre, l'axe X pointe vers la droite et l'axe Y vers le haut.
Pour tester le comportement correct de la classe TurtleBot, on vous fournit un fichier TestTurtleBot.py (ce fichier se trouve sur le site inginious où vous pouvez remettre votre solution.) Ce fichier test contient des tests unitaires pour votre classe TurtleBot qui doit se trouver dans un fichier TurtleBot.py.
Vous pouvez aussi vérifier que le comportement de votre robot est correct en vérifiant que ce qu'il dessine sur l'écran correspond à ce que vous attendez.
Maintenant, on veut étendre la fonctionnalité des robots. A vos deux classes XYRobot et TurtleBot , ajoutez des méthodes pour:
Plus spécifiquement, il faut ajouter les deux méthodes suivantes:
- history() : retourne l'historique des actions précédentes, comme une liste du style: [('forward', 50), ('left', 90), ('forward', 50), ...]
- unplay() : rejouer les actions précédentes dans le sens inverse et vider l'historique après avoir rejoué ces actions.
Même si faire du copier-coller de code entre ces deux classes est encore permis pour cette exercice, dans l'étapes suivantes on utilisera l'héritage pour éviter ce copier-coller en ajoutant une classe mère avec le code commun entre ces deux classes.
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.
Si vous n'avez pas encore utilisé l'héritage lors de l'étape précédente, il est fort probable que vous ayez créé des méthodes très similaires dans les deux classes XYRobot et TurtleBot. Ces deux classes représentent tous les deux un robot ayant une mémoire contenant les actions déjà effectuées ainsi qu'une méthode pour défaire ces actions. Une bonne manière d'éviter le code redondant (recopié/dupliqué dans les deux classes) est de le mettre dans un classe mère Robot commune à ces deux classes, et de déclarer XYRobot et TurtleBot comme des classes filles de cette classe. En particulier, la classe mère peut contenir tout le code pour retenir les actions effectuées et de les refaire dans le sens inverse.
Lors de cet étape on vous demande donc de :
Rejouez les tests unitaires TestXYRobot et TestTurtleBot de l'étape précédente sur la nouvelle version des classes XYRobot et TurtleBot qui héritent de leur nouvelle clases mère. Si tout va bien ces tests doivent toujours fonctionner. Si ce n'est pas le cas, adapter le code ou les tests où nécessaire.
Le diagramme de classes suivant résume les différentes classes et méthodes à implémenter lors de cette mission :
Un fichier Robot.py qui contient la classe mère Robot avec le code de gestion de l'historique.
(Si vous n'êtes pas arrivé à cette étape, remettez simplement un fichier vide ici.)
Un fichier XYRobot.py qui contient la classe XYRobot qui hérite de Robot.
(Si vous n'êtes pas arrivé à l'étape avec l'héritage de la classe Robot, remettez la version de votre classe XYRobot sans héritage ici.)
Un fichier TurtleBot.py qui contient la classe TurtleBot qui hérite de Robot.
(Si vous n'êtes pas arrivé à l'étape avec l'héritage de la classe Robot, remettez la version de votre classe TurtleBot sans héritage ici.)
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.
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.
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.
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.
A l'issue de cette mission, chacun d'entre vous :
Comment bien préparer la mission?
Assister au cours et regarder les capsules vidéos pour comprendre les notions et concepts qui seront abordés.
Lire attentivement et comprendre le chapitre sur Linked lists dans la partie Objects du syllabus théorie :
- 7 - Linked lists
- Embedded references
- The Node class
- Linked lists as collections
- Linked lists and recursion
- Infinite lists
- Ambiguity between lists and nodes
- Modifying lists
- Wrappers and helpers
- The LinkedList class
Essayer et comprendre le code développé dans le syllabus et qui se trouve aussi dans l'annexe correspondant :
- Appendix - Source code of linked lists
- LinkedList class
- Node class
- Creating and using LinkedList objects
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.
Répondre aux questions à choix multiples et aux autres questions 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.
Les questions à choix multiples de cette mission sont accessibles en ligne depuis https://inginious.info.ucl.ac.be/course/LSINF1101-PYTHON/Session11_QCM.
Répondez aux questions suivantes:
Question 1 : Manipuler une liste vide
Cette question concerne l'utilisation de la classe LinkedList dont le code se trouve dans l'annexe suivante du syllabus : Appendix - Source code of linked lists
Utilisez la classe LinkedList pour créer une liste chaînée vide l.
Donnez une instruction Python pour imprimer le contenu de cette liste l.
Quel résultat sera affiché si on essaie d'imprimer la liste l avec l'instruction print(l)? Expliquez.
Donnez une instruction Python pour imprimer la taille de cette liste l .
Quel résultat sera affiché si on essaie d'imprimer la taille avec l'instruction print(l.__length)? Expliquez.
Question 2 : Remplir la liste
Pour ajouter des éléments à une liste vide, quelqu'un a écrit les instructions suivantes:
l = LinkedList() l.add(3) l.add(2) l.add(1) l.print()
Mais quelqu'un d'autre à écrit:
l = LinkedList() l.add(Node(3)) l.add(Node(2)) l.add(Node(1)) l.print()
Dans les deux cas, exécuter l'instruction l.print() affichera [ 1 2 3 ].
Lequel des deux fragments de code ci-dessus vous semble correct? Pourquoi l'autre imprime quand-même le même résulat?
Indice : qu'est-ce qui se passe si on exécute l'instruction print(Node(Node(Node(1))))? Pouvez-vous expliquer?
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() [ ]
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 ]
Ajoutez à la classe LinkedList une méthode add_to_end(self, cargo) pour ajouter un noeud en queue de la liste. Ajoutez d'abord un nouvel attribut last dans la méthode d'initialisation pour garder une référence vers ce dernier élément. Changez ensuite la méthode add pour assigner cette référence lors de l'ajout du premier noeud, et la méthode remove pour remettre cette référence à None lorsque la liste est de nouveau vide. Implémentez ensuite la méthode add_to_end.
Étapes de l'ajout d'un noeud dans une liste chainée :
Pour plus de détails sur les étapes, allez voir le catalogue : Ajout d'un noeud dans une liste chainée .
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.
En Python il est possible d'imbriquer une classe dans une autre. Ceci peut être utile si une classe n'est utilise que par une seule autre classe. C'est le cas ici avec la classe Node. Ce n'est qu'une classe auxiliaire pour la classe LinkedList. Adaptez le code de votre classe LinkedList en imbriquant le code de la classe Node dedans. Il suffit d'indenter le code de la classe Node et de changer chaque référence à la classe Node à l'interieur de la classe LinkedList par self.Node.
Quels sont les avantages et désavantages d'imbriquer la classe Node dans la classe LinkedList?
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.
Dessinez complètement une telle liste chainée contenant les trois strings "abc", "def" et "xyz".
Expliquez en français et dessinez les opérations à effectuer pour ajouter un Node contenant "aaa" dans cette liste.
Même question avec un Node contenant "ghi".
Même question avec un Node contenant "def".
Même question avec un Node contenant "zzz".
Lors de la mission précédente, les tests unitaires avec unittest ont été introduits. Créez un test unitaire pour tester la classe LinkedList. Ce test doit contenir des tests pour les différentes méthodes de la classe LinkedList comme size(), first() ou add(valeur) (code original), remove() (question 4.2.6), add_to_end(valeur) (question 4.2.7) ou insert(valeur) (question 4.2.10). Pour vous mettre sur le bon chemin, votre classe test aura la structure suivante:
import unittest class LinkedListTest(unittest.TestCase): """Classe de test utilisé pour tester la classe LinkedList""" def test_size(self): """Test de la methode size() de la classe LinkedList.""" # ... assert*(...) ... def test_first(self): """Test de la methode first() de la classe LinkedList.""" # ... assert*(...) ... def test_add(self): """Test de la methode add(valeur) de la classe LinkedList.""" # ... assert*(...) ... def test_remove(self): """Test de la methode remove() de la classe LinkedList.""" # ... assert*(...) ... def test_add_to_end(self): """Test de la methode add_to_end(valeur) de la classe LinkedList.""" # ... assert*(...) ... def test_insert(self): """Test de la methode insert(valeur) de la classe LinkedList.""" # ... assert*(...) ... if __name__ == '__main__': unittest.main()
Lors de cette dernière mission, vous allez implémenter un classement de résultats de coureurs, chaque résultat représenté par un coureur (ayant un certain nom et âge) et le temps effectué par ce coureur. Ces résultats doivent être ordonnés selon leur temps dans une liste chaînée ordonnée. Le meilleur résultat (le coureur avec le meilleur temps) se trouve en tête de la liste. Le résultat du coureur le plus lent se trouve en queue de la liste.
Pour compléter cette mission vous trouverez sur INGInious déjà une grande partie du code nécessaire, sauf l'implémentation complète de la classe Classement que vous devez produire, ainsi que la classe OrderedLinkedList qu'elle doit utiliser. Vous devez également écrire des classes de test détaillées (ClassementTest et OrderedLinkedListTest) en utilisant le framework de test unittest, pour vérifier votre implémentation de la classe Classement.
Vous aurez accès à une implémentation assez complète d'une classe LinkedList sur laquelle vous pouvez vous baser, ou que pouvez étendre, pour implémenter la classe OrderedLinkedList. L'archive qu'on vous fournira contient également une implémentation primitive de la classe Classement à base d'un dictionnaire. Néanmoins, cette implémentation est encore incomplète (elle ne gère pas correctement la position des coureurs dans le classement). Vous devez la remplacer par votre implémentation. Elle permet toutefois au programme de fonctionner. Il suffit d'exécuter la méthode de classe main() de la classe Main dans le fichier main.py: le programme simulera à la console l'ajout d'un nouveau résultat aléatoire toute seconde.
Avant de commencer lisez bien le code qui vous a été fourni afin que vous comprenez bien sa structure et son comportement.
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.
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).
Implémentez la classe OrderedLinkedList dont vous aurez besoin pour implémenter votre classe Classement.
Implémentez une classe de test OrderedLinkedListTest pour tester le bon fonctionnement de votre classe OrderedLinkedList.
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. """
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.
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.
Justifiez vos tests dans le fichier README.TXT.
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!
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.
Le diagramme de classes suivant résume les différentes classes et attributs qui feront partie de votre solution finale :
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.
Ajoutez également une méthode test correspondante à votre classe test pour vérifier le bon comportement de la méthode __str__.
Ajoutez également une méthode test correspondante à votre classe test pour vérifier le bon comportement de la méthode remove_from_end.
Ajoutez une méthode contains(e) dans la classe LinkedList qui retourne True si la valeur e se trouve dans la liste et False autrement.
Ajoutez également une méthode test correspondante à votre classe test pour vérifier le bon comportement de la méthode contains(e). N'oubliez pas de prendre en compte différents cas comme:
* la liste est vide; * la liste contient un seul élément égal à l'élément cherché; * la liste contient un seul élément différente de l'élément cherché; * la liste contient différents fois un même élément; * la liste contient différents fois l'élément cherché.
Adaptez le code de la classe LinkedList pour créer une classe DoubleLinkedList représentant une liste doublement chaînée. Pour chaque noeud, en plus d'avoir un lien vers le noeud suivant, on ajoute un lien vers le noeud précédent. Ceci permet de parcourir la liste dans les deux sens: avancer en suivant la référence vers le noeud suivant, ou reculer en suivant la référence vers le noeud précédent. Votre classe DoubleLinkedList doit au moins fournir les méthodes suivantes:
Ecrivez également une classe test unitaire TestDoubleLinkedList pour vérifier le bon comportement des différentes méthodes de la classe DoubleLinkedList. Cette classe test doit contenir des tests pour les différentes méthodes de la classe DoubleLinkedList.
Au code de la liste doublement chaînée de la question complémentaire précédente, ajoutez une méthode remove(e) pour supprimer la première occurrence de e de la liste doublement chainée.
Ajoutez également une méthode test correspondante à votre classe test pour vérifier le bon comportement de la méthode remove.
Déterminer la séquence à parcourir :
Soit un intervalle avec un pas
for i in range(a, b, pas) : # Corps de la boucle
Soit itérer sur les indices ;
for index in range(len(l)) : # Corps de la boucle
Soit itérer sur les éléments
for element in l : # Corps de la boucle
Et initialiser les variables de parcours en fonction ;
Exprimer la condition de traitement si nécessaire (ou de sortie de boucle si la liste ne doit pas être parcourue en entier)
Écrire le corps de la boucle
Vérifier les cas particuliers (liste vide, bornes de début et fin de parcours, etc).