Chapitre 2. Programmation orientée objet (POO)
Évaluation des prérequis
Quizz introductif
Exceptionnellement, en cas d’oubli ou de décharge de votre ordinateur, vous pouvez participer au quizz depuis votre smartphone.
Avant tout, vérifier que le son de votre appareil est coupé.
Dans la suite, pour participer au quizz, il vous sera demandé :
- d’entrer un code PIN. Ce code PIN est affiché au tableau pendant les minutes qui précèdent le lancement du quizz.
- de choisir un pseudo. Veuillez s’il vous plaît choisir comme pseudo votre prénom pour que l’on puisse identifier les scores au cours du quizz.
Une fois ces deux étapes réalisées, vous devrez patienter le temps que tous les élèves de la classe soient connecté-e-s.
Attention, chaque question à choix multiples du quizz est chronométrée (20 à 30 secondes) et plus vous êtes rapide, plus vous recevez de points !
Pour rejoindre la salle d’attente du quizz, rendez-vous à l’adresse www.kahoot.it et suivre les étapes proposées.
Information destinée au/à la professeur-e
Pour projeter puis lancer le quizz, réaliser les étapes ci-dessous.
- Cliquez sur le lien donné ci-apprès.
- Cliquez sur le bouton Connexion (si vous avez déjà un compte Kahoot) ou sur le bouton S’inscrire pour vous créer un compte Kahoot.
- La page vous proposant des forfaits payants est susceptible de s’afficher. Scrollez vers la bas et choisissez Continue with basic qui permet une utilisation gratuite de Kahoot.
- Ouvrez la salle d’attente du quizz en appuyant sur le bouton Commencer.
- Les élèves se connectent à l’aide du code PIN depuis leur téléphone ou leur ordinateur, leurs prénoms apparaissent à l’écran.
- Lorque toute la classe est connectée, appuyez sur le bouton Commencer.
Correction du QCM (Google Colab)
Activités d’introduction
Activité 1. Voitures
Objectif. Découvrir le vocabulaire de la POO
Enoncé
Pour découvrir le vocabulaire de la POO, prenons l'exemple de voitures.
Définir la catégorie d'objets Voiture
c'est lister l'ensemble de ses caractéristiques et fonctionnalités. Par exemple donnons une définition minimale d'une catégorie Voiture
.
- La catégorie
Voiture
a pour caractéristiques :- couleur
- nombre de places
- motorisation
- La catégorie
Voiture
a pour fonctionnalités :- avancer
- reculer
- freiner
- tourner à droite ou à gauche
- Une
voiture_1
en particulier est une représentante de la catégorieVoiture
. La valeur de chacune de ses caractéristiques est spécifique. Par exemple :- couleur :
'rouge'
- nombre de places :
5
- motorisation :
'essence'
Voiture
. Par exemple, unevoiture_2
pourrait avoir les caractéristiques suivantes :- couleur :
'rouge'
- nombre de places :
7
- motorisation :
'électrique'
- couleur :
- Contrairement aux valeurs des caractéristiques qui peuvent être différentes entre représentants de la catégorie
Voiture
, tous les représentants de la catégorieVoiture
partagent les mêmes fonctionnalités c'est-à-dire :- avancer
- reculer
- freiner
- tourner à droite ou à gauche
Compléter le tableau ci-après avec les mots suivants : Classe, Instance, Méthodes, Attributs.
Vocabulaire courant | Vocabulaire de la POO |
---|---|
Catégorie d'objets | ... d'objets |
Représentant d'une catégorie d'objets | ... d'une classe d'objets |
Caractéristiques d'une catégorie d'objets | ... d'une classe d'objets |
Fonctionnalités d'une catégorie d'objets | ... d'une classe d'objets |
Correction
Vocabulaire courant | Vocabulaire de la POO |
---|---|
Catégorie d'objets | Classe d'objets |
Représentant d'une catégorie d'objets | Instance d'une classe d'objets |
Caractéristiques d'une catégorie d'objets | Attributs d'une classe d'objets |
Fonctionnalités d'une catégorie d'objets | Méthodes d'une classe d'objets |
Activité 2. Danse de tortues
Objectif. Utiliser les méthodes d’une classe d’objets prédéfinie
- Programmes à compléter (Google Colab)
- Correction (Google Colab)
Activité 3. Points du plan
Objectif. Définir une nouvelle classe d’objets
- Programmes à compléter (Google Colab)
- Correction (Google Colab)
Travaux pratiques
TP1. Points, segments et polygones
Objectifs. Définir des classes d’objets, programmer avec des objets
- Programmes à compléter (Google Colab)
- Correction (Google Colab)
TP2. Listes, files et piles
Objectif. Implémenter listes, files et piles par des classes d’objets sans
utiliser les types construits Python préexistants (tuple
, list
, dict
)
- Programmes à compléter (Google Colab)
- Correction (Google Colab)
TP3. Bulles
Objectif. Programmmer une animation à partir de classes d’objets
Énoncé
Remarque. Exercice adapté du sujet de Bac Mayotte-Liban, 18 mai 2022
Le but de cette activité est de simuler le comportement d'une mousse composées de bulles multicolores qui se déplacent et fusionnent entre elles. La vidéo suivante montre le résutat final souhaité.
Voici l'ensemble des règles qui définissent le comportement de la mousse :
- La fenêtre d'affichage est un carré de 400 pixels de côté.
- La mousse est constituée au départ d'un nombre défini de bulles dont les couleurs, les positions les vitesses et les tailles respectives sont générées aléatoirement.
- Les bulles ne peuvent pas s'échapper : elles rebondissent sur les bords de la fenêtre d'affichage.
- Lorsque deux bulles se rencontrent, elles fusionnent. La bulle la plus petite est absorbée par la bulle la plus grande qui conserve sa couleur, augmente de taille et voit sa vitesse diminuer.
- À chaque fusion, une nouvelle bulle remplace la bulle qui vient d'être absorbée.
Pour commencer le TP, ouvrir et forker ce projet Replit à compléter. Ce projet Replit est divisé en trois fichiers :
dessin.py
: module fournissant des fonctions de dessin. Le code de ce module ne sera pas étudié.bulles.py
: module contenant les déclarations incomplètes des classesBulles
etMousse
. Ce fichier sera modifié au fur et à mesure de l'activité.main.py
: module principal de test. Le code de chaque question est réuni dans une fonction à tester. Pour certaines questions, il est demandé de modifier le code à tester.
Question 1.
- Dans le console Unix, saisir et valider la commande
python main.py
pour tester l'instanciation et l'affichage d'une bulle. Relancer plusieurs fois la commande pour constater la variabilité aléatoire. Quelle fonction Python standard a été utilisée pour obtenir ce comportement aléatoire ? Afficher avec la fonctionprint
les coordonnées de la bulle affichée. Que peut-on en déduire sur la position de l'origine du repère et l'orientation des axes ? - Dans le fichier
main.py
, modifier le code à tester de la fonctionquestion1
afin d'instancier et d'afficher deux bulles simultanément. Vérifier ensuite le résultat. - On rappelle que l'aire d'un disque est donnée par la formule \(\mathscr{A}_{\text{disque}} = \pi r^2\) où \(r\) désigne le rayon du disque. Ajouter à la classe
Bulle
une méthodeaire
qui renvoie l'aire deself
en pixels carrés. On pensera à importer la constantepi
depuis le modulemath
. Compléter ensuite le code à tester de la fonctionquestion1
pour tester la méthodeaire
par un affichage dans la console. - On se place dans un repère orthonormé. Soit deux points \(A(x_A\,; y_A)\) et \(B(x_B\,; y_B)\). La distance séparant ces deux points est donnée par la formule \(AB = \sqrt{(x_B - x_A)^2 + (y_B - y_A)^2}\). Ajouter à la classe
Bulle
une méthodedistance_centres
qui renvoie la distance entre les centres deself
et d'une autre bulle. On pensera à importer la fonctionsqrt
du modulemath
. Tester ensuite votre code comme dans la question précédente. - Afin de déterminer quand fusionner deux bulles, il faut établir si deux bulles sont entrées en contact l'une avec l'autre. Dans la classe
Bulles
, modifier la méthodebulles_en_contact
afin qu'elle renvoieTrue
siself
et une autre bulle sont en contact etFalse
dans le cas contraire. Aide. La figure ci-dessous donne un critère indiquant si deux bulles sont en contact ou non. - Identification de la grande bulle et de la petite bulle ;
- fusion des bulles ;
- remplacement dans la liste de la bulle absorbée par une nouvelle bulle et affichage de cette nouvelle bulle.
Question 2.
Dans cette question, est présentée la méthode d'animation. Le principe est de définir une fonctionpas
qui représente une étape élémentaire de l'animation. Cette étape élémentaire sera répétée avec une fréquence de 25 répétitions par seconde pour donner l'illusion du mouvement. Dans cette question, l'étape élémentaire consiste simplement à l'instanciation et l'affichage d'une bulle. On va donc accumuler de nombreuses bulles dans la fenêtre d'affichage. Tout en bas du fichier main.py
, ajouter le caractère #
avant question1()
afin de neutraliser cette commande. Retirer juste en dessous le caractère #
avant question2()
puis exécuter le programme main.py
. Expliquez pourquoi les bulles sont rassemblées dans un carré au centre de la fenêtre d'affichage.
Question 3.
Tout en bas du fichiermain.py
, ajouter le caractère #
avant question2()
afin de neutraliser cette commande. Retirer juste en dessous le caractère #
avant question3()
puis exécuter le programme main.py
. Modifier le code de la fonction question3
afin d'afficher et déplacer simultanément deux bulles. Dans la méthode deplacer
de la classe Bulles
à quoi servent les deux branchements conditionnels ? Dans la méthode fusion
de la classe Bulle
, ajouter des commentaires afin d'expliquer le rôle de chaque ligne.
Question 4.
Tout en bas du fichiermain.py
, neutraliser la commande question3()
et activer la commande question4()
. Exécuter le code activé. Lorsqu'on crée un objet de la classe Mousse
, une série d'objets de la classe Bulle
sont créés et stocké dans une liste Python. Quel est le nombre de bulles créées par défaut à l'instanciation d'un objet de classe Mousse
? Modifier le code de la fonction question4
pour que 15 bulles soient affichées simultanément.
Question 5.
Dans la classeMousse
à quoi sert la méthode afficher
? En s'inspirant de cette méthode, compléter la méthode deplacer
de la classe Mousse
. Tout en bas du fichier main.py
, neutraliser la commande question4()
et activer la commande question5()
. Exécuter le code activé pour vérifier le bon déplacement des bulles.
Question 6.
La méthodecollision
de la classe Mousse
sert à prendre en charge l'ensemble des évenements lorsque deux bulles entrent en contact :
collision
. Tout en bas du fichier main.py
, neutraliser la commande question5()
et activer la commande question6()
. Exécuter le code activé pour vérifier la fusion des bulles. Dans la classe Mousse
, à quoi sert la méthode fusions
?
Exercices type Bac
Laser game (Métropole, 11 mai 2022)
Les participants à un jeu de laser game sont répartis en équipes et s’affrontent dans ce jeu de tir, revêtus d’une veste à capteurs et munis d’une arme factice émettant des infrarouges.
Les ordinateurs embarqués dans ces vestes utilisent la programmation orientée objet pour modéliser les joueurs. La classe Joueur
est définie comme suit :
class Joueur:
def __init__(self, pseudo, identifiant, equipe):
"""Constructeur"""
self.pseudo = pseudo
self.equipe = equipe
self.id = identifiant
self.nb_de_tirs_emis = 0
self.liste_id_tirs_recus = []
self.est_actif = True
def tire(self):
"""Méthode déclenchée par l'appui sur la gachette"""
if self.est_actif:
self.nb_de_tirs_emis = self.nb_de_tirs_emis + 1
def est_determine(self):
"""Méthode qui renvoie True si le joueur réalise un grand nombre de tirs"""
return self.nb_de_tirs_emis > 500
def subit_un_tir(self, id_recu):
"""Méthode déclenchée par les capteurs de la veste"""
if self.est_actif:
self.est_actif = False
self.liste_id_tirs_recus.append(id_recu)
- Parmi les instructions suivantes, recopier celle qui permet de déclarer un objet
joueur1
, instance de la classeJoueur
, correspondant à un joueur dont le pseudo est"Sniper"
, dont l’identifiant est319
et qui est intégré à l’équipe"A"
:- Instruction 1 :
joueur1 = ["Sniper", 319, "A"]
- Instruction 2 :
joueur1 = new Joueur["Sniper", 319, "A"]
- Instruction 3 :
joueur1 = Joueur("Sniper", 319, "A")
- Instruction 4 :
joueur1 = Joueur{"pseudo": "Sniper", "id": 319, "equipe": "A"}
Réponse attendue
Instruction 3 :
joueur1 = Joueur("Sniper", 319, "A")
Explications. Pour déclarer une instance de la classe
Joueur
, on écrit le nom de la classe suivi de parenthèses contenant la liste des valeurs prises par les paramètres positionnels obligatoires du constructeur de cette classe, icipseudo
,identifiant
,equipe
. - Instruction 1 :
- La méthode
subit_un_tir
réalise les actions suivantes. Lorsqu’un joueur actif subit un tir capté par sa veste, l’identifiant du tireur est ajouté à l’attributliste_id_tirs_recus
et l’attributest_actif
prend la valeurFalse
(le joueur est désactivé). Il doit alors revenir à son camp de base pour être de nouveau actif.- Écrire la méthode
redevenir_actif
qui rend à nouveau le joueur actif uniquement s’il était précédemment désactivé.Réponse attendue
Le symbole
...
représente ci-après le début de la classeJoueur
qui n'a pas été écrit. On propose ci-dessous deux solutions possibles, la première étant plus élégante, utilisant l'opérateur logiquenot
.Solution 1.
Solution 2.
Remarque. La méthode
redevenir_actif
est une opération de type opérateur : elle modifie l'instance de classe en changeant la valeur de son attributest_actif
. La méthoderedevenir_actif
ne renvoie donc rien d'où l'absence du mot-cléreturn
. - Écrire la méthode
nb_de_tirs_recus
qui renvoie le nombre de tirs reçus par un joueur en utilisant son attributliste_id_tirs_recus
.Réponse attendue
Le symbole
...
ci-après représente le début de la classeJoueur
qui n'a pas été écrit.Explications. Dans le constructeur
__init__
de la classeJoueur
, l'attributliste_id_tirs_recus
est initialisé comme liste vide[]
. La méthodesubit_un_tir
de la classeJoueur
ajoute en bout de cette liste (avec la méthode de listeappend
) l'identifiant de chaque joueur qui toucheself
avec son laser. Ainsi, pour connaître le nombre de tirs reçus, il suffit de connaître la longueur de la listeliste_id_tirs_recus
obtenu à l'aide de la fonctionlen
. La méthodenb_de_tirs_recus
est une opération du type accesseur : elle ne modifie pas l'instance de classe mais fournit une information sur elle : le nombre de tirs recus. On utilise donc le mot-cléreturn
pour renvoyer cette information.
- Écrire la méthode
- Lorsque la partie est terminée, les participants rejoignent leur camp de base respectif où un ordinateur, qui utilise la classe
Base
, récupère les données. La classeBase
est définie par :- ses attributs :
equipe
: nom de l’équipe (str
), par exemple"A"
;liste_des_id_de_l_equipe
qui correspond à la liste (list
) des identifiants connus des joueurs de l’équipe ;score
: score (int
) de l’équipe dont la valeur initiale est1000
;
- ses méthodes :
est_un_id_allie
qui renvoieTrue
si l’identifiant passé en paramètre est un identifiant d’un joueur de l’équipe,False
sinon ;incremente_score
qui fait varier l’attributscore
du nombre passé en paramètre ;collecte_information
qui récupère les statistiques d’un participant passé en paramètre (instance de la classeJoueur
) pour calculer le score de l’équipe .
collecte_information
de la classeBase
. Les caractères...
représentent le début de la classeBase
qui n'a pas été écrit.class Base: ... def collecte_information(self, participant): if participant.equipe == self.equipe : # test 1 for id in participant.liste_id_tirs_recus: if self.est_un_id_allie(id): # test 2 self.incremente_score(-20) else: self.incremente_score(-10)
- Indiquer le numéro du test (test 1 ou test 2) qui permet de vérifier qu’en fin de partie un participant égaré n’a pas rejoint par erreur la base adverse.
Réponse attendue
test 1.
Explications. Lorsqu'un participant (joueur) s'approche d'une base, la méthode
collecte_information
doit prendre en compte le joueur uniquement si son équipe correspond à celle de la base. Cela est assuré par le testparticipant.equipe == self.equipe
oùparticipant
représente le joueur etself
représente la base. Si le joueur est bien de l'équipe de la base, alors la bouclefor
parcours la liste des identifiants de joueurs à l'origine de tirs reçus par le joueur et incrémente le score. Le test 2. permet pour chaque tir reçu de savoir si ce tir provient d'un joueur ennemi ou allié. - Décrire comment varie quantitativement le score de la base lorsqu’un joueur de cette équipe a été touché par le tir d’un coéquipier.
Réponse attendue
Lorsqu'un joueur de cette équipe a été touché par le tir d'un coéquipier (si
self.est_un_id_allie(id)
renvoieTrue
, test 2.), 20 points sont retirés au score de l'équipe.
- ses attributs :
- On souhaite accorder à une base un bonus de 40 points pour chaque joueur de son équipe particulièrement déterminé (qui réalise un grand nombre de tirs). On a réécrit ci-dessous la méthode
collecte_information
que l'on souhaite modifier.Recopier et compléter la méthodeclass Base: ... def collecte_information(self, participant): if participant.equipe == self.equipe : # test 1 for id in participant.liste_id_tirs_recus: if self.est_un_id_allie(id): # test 2 self.incremente_score(-20) else: self.incremente_score(-10) # si le participant réalise un grand nombre de tirs ... # le score de la base augmente de 40 points ...
collecte_information
en remplaçant les deux derniers...
par les bonnes insructions. Utiliser les méthodes des classesJoueur
etBase
.Réponse attendue
class Base: ... def collecte_information(self, participant): if participant.equipe == self.equipe : # test 1 for id in participant.liste_id_tirs_recus: if self.est_un_id_allie(id): # test 2 self.incremente_score(-20) else: self.incremente_score(-10) # si le participant réalise un grand nombre de tirs if participant.est_determine(): # le score de la base augmente de 40 points self.incremente_score(40)
Remarque. On utilise la méthode
est_determine
de la classeJoueur
pour tester la "détermination" du joueurparticipant
. C'est une méthode de classe, attention à penser aux parenthèses ! On ne précise aucun argument dans les parenthèses car cette méthode prend pour unique paramètreself
. L'examen de cette méthode dans la classeJoueur
indique qu'un joueur est considéré comme déterminé s'il a réalisé plus de 500 tirs. -
On suppose l'existence d'une troisième classe
Equipe
dont on donne une extrait de la définition ci-dessous.class Equipe: def __init__(self, nom): self.nom = nom self.liste_joueurs = [] def ajouter_joueur(self, joueur): ...
-
L'attribut
self.liste_joueur
de la classeEquipe
est un tableau (typelist
) au départ vide qui va contenir la liste des joueurs de l'équipe, c'est-à-dire une liste d'objets de la classeJoueur
. Compléter la définition de la méthodeajouter_joueur
de la classeEquipe
permettant d'ajouter un joueur à l'équipe. -
Écrire une méthode
est_determinee
de la classeEquipe
qui renvoieTrue
si la proportion de joueurs déterminés de cette équipe est supérieure ou égale à 50% etFalse
sinon.
-
L'attribut