Correction : Exercices POO

Utilisation d'objet ( travail papier-crayon )

Instanciation des objets et appel de leurs méthodes

Code complet des méthodes


class Carte:
	def __init__(self, nom, couleur):
		# Affectation de l'attribut nom et de l'attribut couleur
		couleurs = ('CARREAU', 'COEUR', 'TREFLE', 'PIQUE')
		noms = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'Valet', 'Dame', 'Roi', 'As']
		valeurs = {'2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9, '10': 10, 'Valet': 11, 'Dame': 12, 'Roi': 13, 'As': 14}
		
		self.couleur = couleurs[couleur]
		self.nom = noms[nom]
		self.valeur = valeurs[self.nom]
		
	def set_nom(self, nom):
		# Mutateur de l'attribut nom (de la liste noms)
		self.nom = nom		
	
	def get_nom(self):
		# renvoie le nom de la carte (de la liste noms): Accesseur
		return self.nom
		
	def get_couleur(self):
		# renvoie la couleur de la carte (de la liste couleur): Accesseur
		return self.couleur
		
	def get_valeur(self):
		# renvoie la valeur de la carte (du dictionnaire valeurs) : Accesseur
		return self.valeur
		
	def egalite(self, carte):
		''' Renvoie True si les cartes self et carte ont même valeur, False sinon
		carte: Objet de type Carte
		'''
		if self.valeur == carte.get_valeur:
			return True
		else :
			return False
		
	def est_superieure(self, carte):
		''' Renvoie True si la valeur de self est supérieure à celle de carte, False sinon
		carte: Objet de type Carte
		'''
		if self.valeur > carte.get_valeur():
			return True
		else :
			return False
		
	def est_inferieure(self, carte):
		''' Renvoie True si la valeur de self est inférieure à celle de carte, False sinon
		carte: Objet de type Carte
		'''
		return self.valeur < carte.get_valeur():
			

Commentaires :

Des cercles

Création de la classe

La consigne était que la classe n'ait qu'un seul attribut : en effet, un cercle est entièrement défini par son rayon, lui rajouter une surface et un périmètre comme attributs supplémentaires est superflu et donc inutile.

Par contre, rien n’empêche d'utiliser des variables locales dans les méthodes pour le calcul de la surface et du périmètre avant de retourner ces valeurs, même si ce n'est pas indispensable ( on peut bien entendu retourner directement le résultat du calcul ).


from math import pi

class Cercle:

    def __init__(self, rayon): # passage du rayon en argument au constructeur
        self.rayon = rayon

    def surface(self):
        return pi*self.rayon**2

    def perimetre(self):
        return 2*pi*self.rayon

    def est_plus_grand(self, c): # c est un argument de type 'Cercle'
        return self.rayon > c.rayon # comparaison de l'attribut 'rayon' de self et de l'objet passé en argument et renvoi du résultat
			

Instanciation des objets

On pouvait créer 5 instances complètement séparées de Cercle, ou alors les regrouper dans une liste comme dans le TP "Champagne !" ; rien n'est imposé !

Par contre, il faut penser à passer la valeur du rayon en argument lors de l'instanciation : le constructeur attend ce paramètre.


c1 = Cercle(5)
c2 = Cercle(21.2)
c3 = Cercle(15)
c4 = Cercle(6)
c5 = Cercle(9.7)
			

Appel des méthodes surface() et perimetre()


>>> c1.perimetre()
31.41592653589793

>>> c5.surface()
295.5924527762636
			

Méthode de comparaison

Il faut bien comprendre comment fonctionne la méthode est_plus_grand():


>>> c2.est_plus_grand(c4)
True		
			

Affichage d'un objet

  1. si on se contente d'un print sur un objet, ce que l'on affiche en réalité est son adresse en mémoire :
    
    c1 = Cercle(18)
    
    print(c1)
    
    >>> <__main__.Cercle object at 0x7f7196be6e50>
    				

    Il se passe d'ailleurs la même chose si on utilise print avec le nom d'une fonction ( ou d'une méthode ) en oubliant les parenthèses : au lieu d'appeler la fonction et d'afficher le résultat qu'elle renvoie, on affiche en fait l'adresse en mémoire de la fonction.

  2. Code de la méthode __str__ :
    
    class Cercle:
    
        ...
    
        def __str__(self):
            return 'Rayon = ' + str(self.rayon)
    
    	...
    					

Des chiens

Classe Chien


from random import shuffle

class Chien :

    def __init__(self, nom, aboiement, points_sante = 100):
        self.nom = nom
        self.points_sante = points_sante
        self.aboiement = 'Grrr...' + aboiement

    def mordre(self, autre_chien):
        autre_chien.points_sante -= 10

    def manger(self):
        self.points_sante += 20

    def grogner(self):
        return self.aboiement

    def machouiller(self, chaine):
        chaine = list(chaine)
        shuffle(chaine)
        chaine = "".join(chaine)
        return chaine		
			

Tout cela semble fonctionner...mais respecte-t-on bien tous les concepts de la POO ? En fait, non : on modifie directement l'attribut d'un autre objet dans la méthode mordre() ( ligne 12 ), ce qui ne respecte pas le principe d'encapsulation des attributs : seul autre_chien devrait pouvoir modifier son attribut points_sante.

Il faudrait donc prévoir dans la classe une méthode destinée à modifier indirectement cet attribut à partir d'un autre objet; une telle méthode est appelée un mutateur ( ou setter en anglais ) :


def modifie_points_sante(self):
	self.points_sante -= 10	
			

La méthode mordre() appellerait alors cette méthode, à partir de l'objet autre_chien :


def mordre(self, autre_chien):
     autre_chien.modifie_points_sante()
			

Utilisation de la classe

Instancier quelques chiens ayant des noms et des aboiements différents :


>>> medor = Chien('Medor', 'ouaf') # valeur de points_sante par défaut ( 100 )
>>> kiki = Chien('Kiki', 'wah-wah', 50) # valeur de points_sante = 50
			

Faire manger un des chiens et vérifier que ses points de santé ont bien augmenté :


>>> medor.manger()

>>> medor.points_sante
120
			

Faire grogner un chien :


>>> medor.grogner()
'Grrr...ouaf'
			

Faire mâchouiller à un chien une chaîne de caractères quelconque :


>>> kiki.machouiller('Au pied!')
'!uepdAi '
			

Faire mordre un chien par un autre et vérifier que ses points de santé ont bien baissé :


>>> medor.mordre(kiki)

>>> kiki.points_sante
40 
			

Une horloge


from time import sleep

class Horloge:

    def __init__(self, heure, minutes, secondes):
        self.heure = heure
        self.minutes = minutes
        self.secondes = secondes

    def affiche(self):
        print(self.heure, ':', self.minutes, ':', self.secondes)

    def tic_tac(self):
        self.secondes += 1

        if self.secondes == 60:
            self.secondes = 0
            self.minutes += 1
            if self.minutes == 60:
                self.minutes = 0
                self.heure += 1
                if self.heure == 24:
                    self.heure = 0

horloge = Horloge(13,59,55)

while True:
    horloge.affiche()
    sleep(1)
    horloge.tic_tac()    		
    		

Des boîtes


from random import randint

class Boite:

    def __init__(self, longueur, largeur, hauteur):
        self.longueur = longueur
        self.largeur = largeur
        self.hauteur = hauteur

    def volume(self):
        return self.longueur * self.largeur * self.hauteur

    def rentre_dans(self, autre_boite):
        return autre_boite.longueur > self.longueur and autre_boite.largeur > self.largeur and autre_boite.hauteur > self.hauteur # on teste si les TROIS dimensions de la deuxième boîte sont plus petites

def tri_selection(boites):
    for i in range(len(boites)):
        mini = i
        for j in range(i+1, len(boites)):
            if boites[j].volume() > boites[mini].volume():
                mini = j
        if mini != i:
            boites[i], boites[mini] = boites[mini], boites[i]

# Création du tableau de 20 objets Boite
boites = []
for i in range(20):
    boites.append(Boite(randint(1, 50), randint(1, 50), randint(1, 50)))


# tri de la liste des boîtes
tri_selection(boites)

# Construction de la suite des boîtes gigognes
suite = [boites[0]]

for i in range(1, len(boites)):
    if boites[i].rentre_dans(suite[-1]): # si la boite du plus grand volume possible rentre dans la dernière boîte de la suite
        suite.append(boites[i]) 

# Vérification
for boite in suite:
    print("L =", boite.longueur, "l =", boite.largeur, "h =", boite.hauteur)