POO et récursivité
Modélisation d'appartements¶
Un appartement est constitué (en général) de plusieurs pièces. Dans ces pièces se trouvent un ou plusieurs meubles, qui occupent une surface au sol, diminuant ainsi la surface disponible dans la pièce. L'objectif de cet exercice est de représenter cette situation à l'aide de classes en python. Les questions de cet exercice forment un ensemble, mais il n'est pas nécessaire d'avoir répondu à une question pour aborder la suivante. En particulier, on pourra utiliser les méthodes des questions précédentes même quand elles n'ont pas été codées.
-
On donne le code de la classe
Meuble
. L'attributnom
indique de quel meuble il s'agit (une armoire, un lit, etc.) ; l'attributsurface_sol
represente la surface qu'occupe le meuble au sol, en mètre carrés.1 2 3 4 5
class Meuble: def __init__(self, n, t): """ Meuble, str, float -> NoneType """ self.nom = n self.surface_sol = t
Donner une instruction qui créé une variable
lit
de typeMeuble
, qui représente un lit nommé "Lit Queen Size" (longueur : 2m, largeur 1,6m).1
lit = Meuble("Lit Queen Size", 3.2)
-
On représente une pièce d'un appartement à l'aide de la classe
Piece
. Ses attributs sont les suivants :nom
de typestr
("chambre 1", "cuisine", par exemple).superficie
de typefloat
. Il s'agit de la taille de la pièce en mètre carrés.superficie_occupee
, de typefloat
. Vaut 0 initialement, augmente lorsque l'on ajoute des meubles.-
liste_meubles
, une liste deMeuble
. Initialement vide, contient la liste des meubles présents dans la pièce. -
Écrire le code python qui permet de définir une classe
Piece
possédant les attributs décrits dans l'énoncé. On écrira de plus la signature de la fonction__init__
.1 2 3 4 5 6 7
class Piece: def __init__(self, nom, superficie): """ Piece, str, float -> NoneType """ self.nom = nom self.superficie = superficie self.superficie_occupee = 0 self.liste_meubles = []
-
Écrire une méthode
possede_place
de la classePiece
qui renvoieTrue
si et seulement si la pièceself
possède au moinssurface
mètre carrés disponibles.1 2 3 4
def possede_place(self, surface): """ Piece, float -> bool Détermine si la pièce possède surface m2 disponibles """ return self.superficie_occupee + surface < self.superficie
-
Écrire une méthode
ajoute
de la classePiece
, qui ajoute lemeuble
à la pièceself
, en modifiant l'attributliste_meubles
. Cette méthode mettra également à jour l'attributsuperficie_occupee
en l'incrémentant de la surface au sol occupée par le meuble. Il est cependant possible qu'il n'y ait pas suffisamment d'espace dans la pièce pour accueillir le meuble. Dans ce cas l'attributliste_meuble
ne sera pas modifié. La méthode renverraTrue
si le meuble a effectivement été ajouté à la pièce,False
sinon.1 2 3 4 5 6 7 8
def ajoute(self, meuble): """ Pièce, Meuble -> bool """ # if meuble.surface_sol + self.superficie_occupee < self.superficie: if self.possede_place(meuble.surface_sol): self.superficie_occupee += meuble.surface_sol self.liste_meubles.append(meuble) return True return False
-
Un appartement contient une ou plusieurs pièces. On donne ci-dessous la définition de la classe
Appartement
:1 2 3 4
class Appartement: def __init__(self, c): """ Appartement, [Piece] -> NoneType """ self.contenu = c
-
On suppose que les variables de type
Meuble
suivants ont été correctement définies.1 2 3 4 5
bain = Meuble("Baignoire", 1.2) wc = Meuble("Toilettes", 0.4) lav = Meuble("Lavabo (toilettes)", 0.1) gaz = Meuble("Gazinière", 0.25) ev = Meuble("Évier (cuisine)", 0.15)
Variable lit
bain
wc
lav
gaz
ev
Nom Lit Queen Size Baignoire Toilettes Lavabo (toilettes) Gazinière Évier (cuisine) Surface au sol 3.2 1.2 0.4 0.1 0.25 0.15 Par exemple, la variable
lit
est de typeMeuble
,lit.nom
est"Lit Queen Size"
etlit.surface_sol
vaut3.2
. À l'aide des variables décrites dans le tableau de l'énoncé, écrire le code python qui permet d'instancier une variable de typeAppartement
qui représente l'appartement dont on donne le plan ci-dessous.1 2 3 4 5 6 7 8 9 10
sdb = Piece("Salle de bain", 4.5) sdb.ajoute(wc) sdb.ajoute(bain) sdb.ajoute(lav) sal = Piece("Salon", 27) coul = Piece("Couloir", 4) cuis = Piece("Cuisine", 3) cuis.ajoute(gaz) cuis.ajoute(ev) apt = Appartement([sdb, sal, coul, cuis])
-
Écrire une méthode
prix
de la classeAppartement
, qui étant donné un prix de vente au mètre carré, renvoie le prix de vente total de l'appartement. Celui-ci sera obtenu en calculant la superficie totale (disponible et occupée) de l'ensemble des pièces de l'appartement, que l'on multipliera par le prix au mètre carré passé en paramètre.1 2 3 4 5 6 7
def prix(self, prix_m2): """ Appartement, float -> float Calcule le prix de vente de l'appartement. """ s = 0 for piece in self.contenu: s += piece.superficie return s*prix_m2
-
Écrire une méthode
recherche_place
de la classeAppartement
, qui étant donné unesuperficie
(donnée en mètre carrés) renvoie la liste des pièces où on peut trouversuperficie
mètre carrés disponibles.1 2 3 4 5 6 7 8
def recherche_place(self, superficie): """ Appartement, float -> [Piece] Renvoie la listes des pièces de l'appartement avec plus de superficie mètre carrés disponibles. """ l = [] for piece in self.contenu: if piece.possede_place(superficie): l.append(piece) return l
-
-
Écrire une fonction
recherche_appart
qui étant donné une listecollection
d'appartements dont le prix de vente au mètre carré est de 10 000€, renvoie l'appartement dont le prix de vente est le minimum parmi ceux qui possèdent au moins 4 pièces et dont l'une des pièces possède au moins 20 mètre carrés disponibles. Si aucun appartement de la listecollection
ne satisfait les conditions demandées, alors la fonction renverraNone
. Toute trace de recherche, même incomplète, sera valorisée dans cette question.1 2 3 4 5 6 7 8 9
def recherche_appart(collection): """ [Appartement] -> Appartement | NoneType """ appart_mini = None prix_mini = float("inf") for appart in collection: if appart.prix(10000) < prix_mini and len(appart.contenu) >= 4 and len(appart.recherche_place(20)) > 0: appart_mini = appart prix_mini = appart.prix(10000) return appart
Des étoiles¶
-
Écrire une fonction python
etoiles
qui étant donné un entiern
renvoie la chaine de caractères constituée du caractère*
, répétén
fois. Toute syntaxe python est acceptée.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
def etoiles(n): """ int -> NoneType Affiche n fois le caractère *. Version récursive """ if n == 0: return "" else: avant = etoiles(n - 1) return "*" + avant def etoiles(n): """ int -> NoneType Affiche n fois le caractère *. Version itérative """ s = "" for _ in range(n): s += "*" return s def etoiles(n): """ int -> NoneType Affiche n fois le caractère *. Une ligne """ return "".join(["*" for _ in range(n)])
1 2
print(etoiles(2)) print(etoiles(5))
** *****
Rappel. Si
s1
ets2
sont deux chaînes de caractères, alorss1 + s2
renvoie la concaténation des1
avecs2
. Ainsi,"bonjour" + " ! "
renvoie la chaîne"bonjour ! "
. -
On donne le code des fonctions
f
,g
,h
etk
suivantes.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
def f(n): """ int -> None """ if n == 1: print(etoiles(1)) else: print(etoiles(n)) f(n - 1) def g(n): """ int -> None """ if n == 1: print(etoiles(1)) else: g(n - 1) print(etoiles(n))
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
def h(n): """ int -> None """ if n == 1: print(etoiles(1)) else: h(n - 1) print(etoiles(n)) h(n - 1) def k(n): """ int -> None """ if n == 1: print(etoiles(1)) else: print(etoiles(n)) k(n - 1) print(etoiles(n))
On donne également, dans le désordre les affichages réalisés par les instructions
f(3)
,g(3)
,h(3)
, etk(3)
.1
h(3)
* ** * *** * ** *
1
f(3)
*** ** *
1
g(3)
* ** ***
1
k(3)
*** ** * ** ***
Sans justifier votre réponse, déterminer quelle instruction a provoqué quel affichage.
-
On se propose d'étudier l'affichage réalisé par la fonction
u
suivante.1 2 3 4 5 6 7 8 9
def u(n, i): """ int, int -> NoneType On suppose que i <= n. """ if i == n: print(etoiles(n)) else: print(etoiles(i)) u(n, i + 1) print(etoiles(i))
-
Dresser l'arbre d'appel de l'instruction
u(5, 2)
. On représentera les appels successifs les uns en dessous des autres, et on indiquera au bon endroit le long de l'arbre les différents événements d'affichage à l'aide de la ligne de code correspondante. -
En déduire l'affichage réalisé par
u(5, 2)
.1
u(5, 2)
** *** **** ***** **** *** **
-
Quelle erreur soulève l'instruction
u(2, 5)
? Expliquer votre réponse.u(2, 5)
soulève l'erreurRecursionError
, car le cas de base n'est jamais atteint :u(2, 5)
, appelleu(2, 6)
qui appelleu(2, 7)
etc. Ainsi, plus de 1000 appels seront réalisés ce qui déclenchera l'erreur.
-