• Aucun résultat trouvé

Remarque : lorsque dans la définition d'une classe, on souhaite faire appel à une méthode définie dans une autre classe, on doit lui transmettre la référence de l'instance comme premier argument.

C'est ainsi que dans notre script, par exemple, la méthode affiche() de la classe Ion() peut faire appel à la méthode affiche() de la classe Atome() : les informations affichées seront bien celles de l'objet-ion courant, puisque sa référence a été transmise dans l'instruction d'appel :

Atome.affiche(self)

(dans cette instruction, self est bien entendu la référence de l'instance courante).

De la même manière, la méthode constructeur de la classe Ion() fait appel à la méthode constructeur de sa classe parente, dans : Atome.__init__(self, nat)

Exercices

Définissez une classe Domino() qui permette d'instancier des objets simulant les pièces d'un jeu de dominos. Le constructeur de cette classe initialisera les valeurs des points présents sur les deux faces A et B du domino (valeurs par défaut = 0). Deux autres méthodes seront définies :

une méthode affiche_points() qui affiche les points présents sur les deux faces ; une méthode valeur() qui renvoie la somme des points présents sur les deux faces. Exemples d'utilisation de cette classe :

>>> d1 = Domino(2,6) >>> d2 = Domino(4,3) >>> d1.affiche_points() face A : 2 face B : 6 >>> d2.affiche_points() face A : 4 face B : 3

>>> print "total des points :", d1.valeur() + d2.valeur() total des points : 15

>>> liste_dominos = [] >>> for i in range(7): liste_dominos.append(Domino(6, i)) >>> liste_dominos[1].affiche_points() face A: 6 face B: 1 etc., etc. 1.

Définissez une classe CompteBancaire(), qui permette d'instancier des objets tels que compte1, compte2, etc. Le constructeur de cette classe initialisera deux attributs d'instance "nom" et "solde", avec les valeurs par défaut 'Dupont' et 1000. Trois autres méthodes seront définies :

depot(somme) permettra d'ajouter une certaine somme au solde retrait(somme) permettra de retirer une certaine somme du solde

affiche() permettra d'afficher le nom du titulaire et le solde de son compte. Exemples d'utilisation de cette classe :

>>> compte1 = CompteBancaire('Duchmol', 800) >>> compte1.depot(350)

>>> compte1.retrait(200) >>> compte1.affiche()

Le solde du compte bancaire de Duchmol est de 950 euros. >>> compte2 = CompteBancaire()

>>> compte2.depot(25) >>> compte2.affiche()

Le solde du compte bancaire de Dupont est de 1025 euros. 2.

Définissez une classe Voiture() qui permette d'instancier des objets reproduisant le comportement de voitures automobiles. Le constructeur de cette classe initialisera les attributs d'instance suivants, avec les valeurs par défaut indiquées : marque = 'Ford', couleur = 'rouge', pilote = 'personne', vitesse = 0. Lorsque l'on instanciera un nouvel objet Voiture(), on pourra choisir sa marque et sa couleur, mais pas sa vitesse, ni le nom de son

conducteur. Les méthodes suivantes seront définies : - choix_conducteur(nom) permettra de désigner (ou changer) le nom du conducteur - accelerer(taux, duree) permettra de faire varier la vitesse de la voiture. La variation de vitesse obtenue sera égale au produit : taux x duree. Par exemple, si la voiture accélère au taux de 1,3 m/s2 pendant 20 secondes, son gain de vitesse doit être égal à 26 m/s. Des taux négatifs seront acceptés (ce qui permettra de décélérer). La variation de vitesse ne sera pas autorisée si le conducteur est 'personne'. - affiche_tout() permettra de faire apparaître les propriétés présentes de la voiture, c'est-à-dire sa marque, sa couleur, le nom de son conducteur, sa vitesse. Exemples d'utilisation de cette classe :

>>> a1 = Voiture('Peugeot', 'bleue') >>> a2 = Voiture(couleur = 'verte') >>> a3 = Voiture('Mercedes') >>> a1.choix_conducteur('Roméo') >>> a2.choix_conducteur('Juliette') >>> a2.accelerer(1.8, 12) >>> a3.accelerer(1.9, 11)

Cette voiture n'a pas de conducteur ! >>> a2.affiche_tout()

Ford verte pilotée par Juliette, vitesse = 21.6 m/s. >>> a3.affiche_tout()

Mercedes rouge pilotée par personne, vitesse = 0 m/s.

Définissez une classe Satellite() qui permette d'instancier des objets simulant des satellites artificiels lancés dans l'espace, autour de la terre. Le constructeur de cette classe initialisera les attributs d'instance suivants, avec les valeurs par défaut indiquées : masse = 100, vitesse = 0. Lorsque l'on instanciera un nouvel objet Satellite(), on pourra choisir son nom, sa masse et sa vitesse. Les méthodes suivantes seront définies : - impulsion(force, duree) permettra de faire varier la vitesse du satellite. Pour savoir comment, rappelez-vous votre cours de physique : la variation de vitesse subie par un objet de masse m soumis à l'action d'une force F pendant un temps t vaut

. Par exemple : un satellite de 300 kg qui subit une force de 600 Newtons pendant 10 secondes voit sa vitesse augmenter (ou diminuer) de 20 m/s. - affiche_vitesse() affichera le nom du satellite et sa vitesse courante. - energie() renverra au programme appelant la valeur de l'énergie cinétique du satellite. Rappel : l'énergie cinétique

se calcule à l'aide de la formule Exemples d'utilisation de cette classe :

>>> s1 = Satellite('Zoé', masse =250, vitesse =10) >>> s1.impulsion(500, 15)

>>> s1.affiche_vitesse()

vitesse du satellite Zoé = 40 m/s. >>> print s1.energie()

200000

>>> s1.impulsion(500, 15) >>> s1.affiche_vitesse()

vitesse du satellite Zoé = 70 m/s. >>> print s1.energie()

612500 4.

Solution

class Domino:

def __init__(self, pa, pb): self.pa, self.pb = pa, pb

def affiche_points(self): print "face A :", self.pa, print "face B :", self.pb

def valeur(self):

return self.pa + self.pb # Programme de test :

d1 = Domino(2,6) d2 = Domino(4,3) d1.affiche_points() d2.affiche_points()

print "total des points :", d1.valeur() + d2.valeur() liste_dominos = [] for i in range(7): liste_dominos.append(Domino(6, i)) vt =0 for i in range(7): liste_dominos[i].affiche_points() vt = vt + liste_dominos[i].valeur()

print "valeur totale des points", vt 1.

Réfléchissez ! 2.

class Voiture: 3.

def __init__(self, marque = 'Ford', couleur = 'rouge'): self.couleur = couleur self.marque = marque self.pilote = 'personne' self.vitesse = 0

def accelerer(self, taux, duree): if self.pilote =='personne':

print "Cette voiture n'a pas de conducteur !" else:

self.vitesse = self.vitesse + taux * duree

def choix_conducteur(self, nom): self.pilote = nom

def affiche_tout(self):

print "%s %s pilotée par %s, vitesse = %s m/s" % \

(self.marque, self.couleur, self.pilote, self.vitesse)

a1 = Voiture('Peugeot', 'bleue') a2 = Voiture(couleur = 'verte') a3 = Voiture('Mercedes') a1.choix_conducteur('Roméo') a2.choix_conducteur('Juliette') a2.accelerer(1.8, 12) a3.accelerer(1.9, 11) a2.affiche_tout() a3.affiche_tout() class Satellite:

def __init__(self, nom, masse =100, vitesse =0):

self.nom, self.masse, self.vitesse = nom, masse, vitesse

def impulsion(self, force, duree):

self.vitesse = self.vitesse + force * duree / self.masse

def energie(self):

return self.masse * self.vitesse**2 / 2

def affiche_vitesse(self):

print "Vitesse du satellite %s = %s m/s" \ % (self.nom, self.vitesse) # Programme de test :

s1 = Satellite('Zoé', masse =250, vitesse =10) s1.impulsion(500, 15) s1.affiche_vitesse() print s1.energie() s1.impulsion(500, 15) s1.affiche_vitesse() print s1.energie() 4. Exercices

Définissez une classe Cercle(). Les objets construits à partir de cette classe seront des cercles de tailles variées. En plus de la méthode constructeur (qui utilisera donc un paramètre rayon), vous définirez une méthode surface(), qui devra renvoyer la surface du cercle. Définissez ensuite une classe Cylindre() dérivée de la précédente. Le

constructeur de cette nouvelle classe comportera les deux paramètres rayon et hauteur. Vous y ajouterez une méthode volume() qui devra renvoyer le volume du cylindre. (Rappel : Volume d'un cylindre = surface de section x

hauteur). Exemple d'utilisation de cette classe :

>>> cyl = Cylindre(5, 7) >>> print cyl.surface() 78.54

>>> print cyl.volume() 1.

549.78

Complétez l'exercice précédent en lui ajoutant encore une classe Cone(), qui devra dériver cette fois de la classe Cylindre(), et dont le constructeur comportera lui aussi les deux paramètres rayon et hauteur. Cette nouvelle classe possédera sa propre méthode volume(), laquelle devra renvoyer le volume du cône. (Rappel : Volume d'un cône =

volume du cylindre correspondant divisé par 3). Exemple d'utilisation de cette classe :

>>> co = Cone(5,7) >>> print co.volume() 183.26

2.

Définissez une classe JeuDeCartes() permettant d'instancier des objets « jeu de cartes » dont le comportement soit similaire à celui d'un vrai jeu de cartes. La classe devra comporter au moins les trois méthodes suivantes : - méthode constructeur : création et remplissage d'une liste de 52 éléments, qui sont eux-mêmes des tuples de 2 éléments contenant les caractéristiques de chacune des 52 cartes. Pour chacune d'elles, il faut en effet mémoriser séparément un nombre entier indiquant la valeur (2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, les 4 dernières valeurs étant celles des valet, dame, roi et as), et un autre nombre entier indiquant la couleur de la carte (c'est-à-dire 0,1,2,3 pour Cœur, Carreau, Trèfle & Pique). Dans une telle liste, l'élément (11,2) désigne donc le valet de Trèfle, et la liste terminée doit être du type : [(2, 0), (3,0), (3,0), (4,0), ... ... (12,3), (13,3), (14,3)] - méthode nom_carte() : cette méthode renvoie sous la forme d'une chaîne l'identité d'une carte quelconque, dont on lui a fourni le tuple descripteur en argument. Par exemple, l'instruction : print jeu.nom_carte((14, 3)) doit provoquer l'affichage de : As de pique - méthode battre() : comme chacun sait, battre les cartes consiste à les mélanger. Cette méthode sert donc à mélanger les éléments de la liste contenant les cartes, quel qu'en soit le nombre. - méthode tirer() : lorsque cette méthode est invoquée, une carte est retirée du jeu. Le tuple contenant sa valeur et sa couleur est renvoyé au

programme appelant. On retire toujours la première carte de la liste. Si cette méthode est invoquée alors qu'il ne reste plus aucune carte dans la liste, il faut alors renvoyer l'objet spécial None au programme appelant. Exemple d'utilisation de la classe JeuDeCartes() :

jeu = JeuDeCartes() # instanciation d'un objet

jeu.battre() # mélange des cartes

for n in range(53): # tirage des 52 cartes : c = jeu.tirer()

if c == None: # il ne reste plus aucune carte print 'Terminé !' # dans la liste

else:

print jeu.nom_carte(c) # valeur et couleur de la carte 3.

Complément de l'exercice précédent : Définir deux joueurs A et B. Instancier deux jeux de cartes (un pour chaque joueur) et les mélanger. Ensuite, à l'aide d'une boucle, tirer 52 fois une carte de chacun des deux jeux et comparer leurs valeurs. Si c'est la première des 2 qui a la valeur la plus élevée, on ajoute un point au joueur A. Si la situation contraire se présente, on ajoute un point au joueur B. Si les deux valeurs sont égales, on passe au tirage suivant. Au terme de la boucle, comparer les comptes de A et B pour déterminer le gagnant.

4.

Solution

Voir ci-dessous. 1.

#(classes de cylindres et de cônes) : # Classes dérivées - polymorphisme class Cercle:

def __init__(self, rayon): self.rayon = rayon def surface(self):

return 3.1416 * self.rayon**2

class Cylindre(Cercle):

def __init__(self, rayon, hauteur): Cercle.__init__(self, rayon) self.hauteur = hauteur

def volume(self):

return self.surface()*self.hauteur

# la méthode surface() est héritée de la classe parente 2.

class Cone(Cylindre):

def __init__(self, rayon, hauteur):

Cylindre.__init__(self, rayon, hauteur)

def volume(self):

return Cylindre.volume(self)/3

# cette nouvelle méthode volume() remplace celle que

# l'on a héritée de la classe parente (exemple de polymorphisme) cyl = Cylindre(5, 7) print cyl.surface() print cyl.volume() co = Cone(5,7) print co.surface() print co.volume() # Tirage de cartes

from random import randrange class JeuDeCartes:

"""Jeu de cartes"""

# attributs de classe (communs à toutes les instances) : couleur = ('Pique', 'Trèfle', 'Carreau', 'Coeur')

valeur = (0, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 'valet', 'dame', 'roi', 'as') def __init__(self):

"Construction de la liste des 52 cartes" self.carte =[]

for coul in range(4): for val in range(13):

self.carte.append((val +2, coul)) # la valeur commence à 2 def nom_carte(self, c):

"Renvoi du nom de la carte c, en clair"

return "%s de %s" % (self.valeur[c[0]], self.couleur[c[1]])

def battre(self): "Mélange des cartes"

t = len(self.carte) # nombre de cartes restantes # pour mélanger, on procède à un nombre d'échanges équivalent : for i in range(t):

# tirage au hasard de 2 emplacements dans la liste : h1, h2 = randrange(t), randrange(t)

# échange des cartes situées à ces emplacements :

self.carte[h1], self.carte[h2] = self.carte[h2], self.carte[h1]

def tirer(self):

"Tirage de la première carte de la pile"

t = len(self.carte) # vérifier qu'il reste des cartes if t >0:

carte = self.carte[0] # choisir la première carte du jeu del(self.carte[0]) # la retirer du jeu

return carte # en renvoyer copie au prog. appelant else:

return None # facultatif

### Programme test : if __name__ == '__main__':

jeu = JeuDeCartes() # instanciation d'un objet

jeu.battre() # mélange des cartes

for n in range(53): # tirage des 52 cartes : c = jeu.tirer()

if c == None: # il ne reste aucune carte

print 'Terminé !' # dans la liste else:

print jeu.nom_carte(c) # valeur et couleur de la carte

#(On supposera que l'exercice précédent a été sauvegardé sous le nom cartes.py) # Bataille de de cartes

from cartes import JeuDeCartes

jeuA = JeuDeCartes() # instanciation du premier jeu jeuB = JeuDeCartes() # instanciation du second jeu

jeuA.battre() # mélange de chacun

jeuB.battre()

pA, pB = 0, 0 # compteurs de points des joueurs A et B

# tirer 52 fois une carte de chaque jeu : for n in range(52):

cA, cB = jeuA.tirer(), jeuB.tirer()

vA, vB = cA[0], cB[0] # valeurs de ces cartes if vA > vB:

pA += 1 elif vB > vA:

pB += 1 # (rien ne se passe si vA = vB)

# affichage des points successifs et des cartes tirées :

print "%s * %s ==> %s * %s" % (jeuA.nom_carte(cA), jeuB.nom_carte(cB), pA, pB) print "le joueur A obtient %s points, le joueur B en obtient %s." % (pA, pB) 4.

Exercices

Créer vous-même un nouveau module de classes, en encodant les lignes d'instruction ci-dessous dans un fichier que vous nommerez formes.py : class Rectangle:

"Classe de rectangles"

def __init__(self, longueur = 30, largeur = 15):

self.L = longueur

self.l = largeur

self.nom ="rectangle" def perimetre(self):

return "(%s + %s) * 2 = %s" % (self.L, self.l,

(self.L + self.l)*2) def surface(self):

return "%s * %s = %s" % (self.L, self.l, self.L*self.l) def mesures(self):

print "Un %s de %s sur %s" % (self.nom,self.L, self.l) print "a une surface de %s" % (self.surface(),) print "et un périmètre de %s\n" % (self.perimetre(),) class Carre(Rectangle):

"Classe de carrés"

def __init__(self, cote =10):

Rectangle.__init__(self, cote, cote)

self.nom ="carré" if __name__ == "__main__":

r1 = Rectangle(15, 30) r1.mesures() c1 = Carre(13) c1.mesures()

Une fois ce module enregistré, vous pouvez l'utiliser de deux manières : soit vous en lancez l'exécution comme celle d'un programme ordinaire, soit vous l'importez dans un script quelconque ou depuis la ligne de commande, pour en utiliser les classes :

>>> f1 = formes.Rectangle(27, 12) >>> f1.mesures() Un rectangle de 27 sur 12 a une surface de 27 * 12 = 324 et un périmètre de (27 + 12) * 2 = 78 >>> f2 = formes.Carre(13) >>> f2.mesures() Un carré de 13 sur 13 a une surface de 13 * 13 = 169 et un périmètre de (13 + 13) * 2 = 52

On voit dans ce script que la classe Carre() est construite par dérivation à partir de la classe Rectangle() dont elle hérite toutes les caractéristiques. En d'autres termes, la classe Carre() est une classe fille de la classe Rectangle().

Vous pouvez remarquer encore une fois que le constructeur de la classe Carre() fait appel au constructeur de sa classe parente ( Rectangle.__init__() ), en lui transmettant la référence de l'instance (c'est-à-dire self) comme premier argument.

Quant à l'instruction :

if __name__ == "__main__":

placée à la fin du module, elle sert à déterminer si le module est « lancé » en tant que programme (auquel cas les instructions qui suivent doivent être exécutées), ou au contraire utilisé comme une bibliothèque de classes importée ailleurs. Dans ce cas cette partie du code est sans effet.

Solution https://docs.python.org/2.7/reference/datamodel.html#special-method-names 1. http://farmdev.com/src/secrets/magicmethod/ 2.

Références

1 2 3 4