NUMERIQUE ET SCIENCES INFORMATIQUES

Niveau : Terminale générale, enseignement de spécialité NSI

 

D
É
C
O
N
N
E
C
T
É

Programmation orientée objet

1 - Introduction

La classe est un concept de base de la programmation orientée objet.

En langage Python, vous pouvez très bien écrire un script sans définir de classes (c'est ce que nous avons fait jusqu'à présent).

Cependant, vous manipulez forcément des objets (ou instances de classes) : une variable entière est une instance de la classe int, une chaîne de caractères est une instance de la classe str...

Le module pygame fournit une bibliothèque de classes.

Lien vers la video sur Lumni

2 - Définition d'une classe

Une classe est définie par : un nom, des attributs et des méthodes.

Voici un exemple de script qui utilise une classe définie par l'utilisateur.

Nous allons commencer par créer le fichier source CompteBancaire.py (on parlera par la suite du module CompteBancaire) :



		

L'instruction class

Pour définir la nouvelle classe Compte, on utilise l'instruction class.

Une classe possède des fonctions que l'on appelle méthodes et des données que l'on appelle attributs.

Une méthode se définit de la même manière qu'une fonction (on commence par l'instruction def).

Une méthode possède au moins un paramètre qui s'appelle self.

Le paramètre self désigne toutes les instances qui seront créées par cette classe.

7 méthodes sont ainsi définies.

Un seul attribut d'instance est utilisé dans cette classe : solde (à ne pas confondre avec la méthode Solde()).

La méthode constructeur

La méthode constructeur (méthode spéciale __init__()) est exécutée automatiquement lorsque l'on instancie (crée) un nouvel objet de la classe.

Autres méthodes spéciales

Deux autres méthodes spéciales sont utilisées : __add__() et __sub__().

L'écriture cb1+253.2 est équivalente à cb1.__add__(253.2)

L'opérateur + représente ici une addition sur le solde.

L'écriture cb1-1000 est équivalente à cb1.__sub__(1000)

L'opérateur - représente ici une soustraction sur le solde.

>>> cb1.NouveauSolde(500)
>>> print( cb1.Solde())
500.0
>>> cb1.__add__(1000)
Nouveau solde : +1500.00 euros
>>> cb1+2000 # cette écriture est très pratique !
Nouveau solde : +3500.00 euros
>>>

L'instruction if __name__ == '__main__':

Ici, le module est exécuté en tant que programme principal : les instructions qui suivent sont donc exécutées.

Dans le cas où ce module est importé dans un autre programme, cette partie du code est sans effet.

Documentation

La fonction help() est très utile.

On comprend ici l'intérêt de bien documenter ses programmes avec les """docstrings""" :

>>> help(cb1)
Help on instance of Compte in module __main__:

class Compte
| Un exemple de classe :
| gestion d'un compte bancaire
|
| Methods defined here:
|
| Credit(self, somme)
| Crédite le compte de la valeur somme. Retourne le solde.
|
| Debit(self, somme)
| Débite le compte de la valeur somme. Retourne le solde.
|
| NouveauSolde(self, somme)
| Nouveau solde de compte avec la valeur somme.
|
| Solde(self)
| Retourne le solde.
|
| __add__(self, somme)
| x.__add__(somme) <=> x+somme
| Crédite le compte de la valeur somme.
| Affiche 'Nouveau solde : somme'
|
| __init__(self, soldeInitial)
| Initialisation du compte avec la valeur soldeInitial.
|
| __sub__(self, somme)
| x.__sub_(somme) <=> x-somme
| Débite le compte de la valeur somme.
| Affiche 'Nouveau solde : somme'

>>>

La fonction dir() retourne la liste des méthodes et attributs :

>>> dir(cb1)
['Credit', 'Debit', 'NouveauSolde', 'Solde', '__add__',
'__doc__', '__init__', '__module__', '__sub__', 'solde']

Remarques

On peut instancier plusieurs objets d'une même classe :

>>> cb2 = Compte(10000)
>>> print( cb2.Credit(500))
10500.0
>>> cb3 = Compte(6000) # et encore un !
>>> cb3-500
Nouveau solde : +5500.00 euros
>>>

Même si cela n'est pas recommandable, vous pouvez accéder directement aux attributs d'instance :

>>> print( cb2.solde)
10500.0
>>> cb2.solde = 5000.0 # assignation de l'attribut d'instance solde
>>> print( cb2.solde)
5000.0
>>> print( cb2.Solde())
5000.0
>>>

Notez que des méthodes spéciales sont prévues pour personnaliser le mode d'accès aux attributs : __setattr__(), __getattr__()...

Importation d'un module défini par l'utilisateur

L'importation de notre module personnel CompteBancaire se fait de la même façon que pour les modules de base (math, random, time...).

Redémarrer l'interpréteur interactif (Python Shell) :
Shell → Restart Shell

>>> import CompteBancaire
>>> cb = CompteBancaire.Compte(1500)
>>> print( cb.Debit(200))
1300.0
>>> print( cb.solde)
1300.0
>>> cb+2000
Nouveau solde : +3300.00 euros
>>>

Le module CompteBancaire est importé par le programme principal (ici l'interpréteur interactif).
La partie du code qui suit l'instruction if __name__ == '__main__': est ignorée (il n'y a donc pas d'affichage après l'instruction import CompteBancaire).

2. Exercices

Exercice 7.1 ★ On s'intéresse au module CompteBancaire.

Définir une nouvelle méthode Decouvert() de la classe Compte, qui affiche selon le cas Solde positif ou Solde négatif :

A la suite du programme principal, ajouter les lignes suivantes :

    CompteJerome = Compte(2000)
    CompteJerome-3000
    CompteJerome.Decouvert()
    CompteJerome+10000
    CompteJerome.Decouvert()

Le résultat devra être le suivant :

Nouveau solde : -1000.00 euros
Solde négatif
Nouveau solde : +9000.00 euros
Solde positif

Exercice 7.2 ★★ On s'intéresse au module CompteBancaire.

Définir une nouvelle méthode Suivi() qui affiche l'historique du solde.
On pourra définir un nouvel attribut de type list :

A la suite du programme principal, ajouter les lignes suivantes :

    CompteJerome.Debit(5000)
    CompteJerome.Credit(1000)
    CompteJerome.Suivi()

Le résultat devra être le suivant :

[2000.0, 3000.0, 10000.0, 5000.0, 1000.0]

Exercice 7.3 ★★

Le duel de Pokemons

classe

Nous commençons par créer une classe Pokemon. Un Pokemon se définit par (entre autres) :

  • Un attribut nom, correspondant au nom du pokemon.
  • Un attribut pv correspondant à ses points de vie
  • Un attribut pvmax correspondant à ses points de vie maximale égal à pv lors de l'initialisation
  • Un attribut pc correspondant à sa puissance de combat
  • Un type (EAU, FEU, PLANTE, ELECTRIK...)
  • Une méthode EstVivant() qui retourne True si un Pokemon est toujours en vie (pv >0) sinon on retourne False.
  • Une méthode BoitPotion(gain) permettant d'ajouter le gain , devra appeler la fonction spéciale __add__(gain)
  • Une méthode Attaque(pokemon) permettant au Pokémon courant d'attaquer le Pokemon passé en paramètre. Cette méthode inflige des dégâts aux points de vie des Pokemons. Le calcul des dégâts infligés est expliquée plus tard. Au début de la méthode afficher "nom du pokemon1 attaque nom du pokemon2" et à la fin de la méthode afficher "nom du pokemon1" afflige xx dégâts à "nom du pokemon2" puis retranchez au pokemon les dégâts , par l'appel de la fonction spéciale __sub__
  • Une méthode spéciale __add__(gain) qui permet d'additionner un gain à l'attrubut pv sans dépasser l'attribut pvmax. Elle affiche un message "nom pokemon a xx PV"
  • Une méthode spéciale __sub__(degats) qui permet de soustraire des dégâts à l'attribut pv sans atteindre une valeur négative. Elle affiche un message "nom pokemon est KO" si pv=0 et dans tous les cas affiche "il reste xx PV à nom pokemon"

Les Pokemons décrits à travers la classe Pokemon servent de base à la modélisation de ces petites créatures.

N'oubliez pas les docstrings et les commentaires

Programmation de la classe :

Le travail consiste maintenant à décrire les Pokemons en fonction de leur type.

Il existe plus d’une quinzaine de types différents  Nous nous concentrons ici sur quatre catégories:

  • Les Pokemons de type EAU
  • Les Pokemons de type FEU
  • Les Pokemons de type PLANTE
  • Les Pokemons de type ELECTRIK

Calcul simplifié des dégâts :

  • Les Pokemons de type FEU sont super efficaces contre les Pokemons de type PLANTE et leur infligent deux fois plus de dégâts (2*pc). Par contre, ils sont très peu efficaces contre les Pokemons de type EAU ou de type FEU et ne leur infligent que la moitié des dégâts (0.5*pc). Ils infligent des dégâts normaux aux Pokémon de type ELECTRIK.
  • Les Pokemons de type EAU sont super efficaces contre les Pokemons de type FEU et leur infligent deux fois plus de dégâts (2*pc). Par contre, ils sont très peu efficaces contre les Pokémon de type PLANTE ou de type EAU et ne leur infligent que la moitié des dégâts (0.5*pc). Ils infligent des dégâts normaux aux Pokémon de type ELECTRIK.
  • Les Pokemons de type ELECTRIK sont super efficaces contre les Pokemons de type EAU et leur infligent deux fois plus de dégâts (2*pc). Par contre, ils sont très peu efficaces contre les Pokemons de type ELECTRIK ou de type PLANTE et ne leur infligent que la moitié des dégâts (0.5*pc). Ils infligent des dégâts normaux aux Pokémon de type FEU.
  • Enfin, les Pokemons de type PLANTE sont super efficaces contre les Pokemons de type EAU et leur infligentdeux fois plus de dégâts (2*pc). Par contre, ils sont très peu efficaces contre les Pokémon de type PLANTE ou de type FEU et ne leur infligent que la moitié des dégâts (0.5*pc). Ils infligent des dégâts normaux aux Pokémon de type ELECTRIK.

Tableau récapitulatif des dégâts infligés

Défense →
Attaque ↴
FEUEAUELECTRIKPLANTE
FEU½½12
EAU2½1½
ELECTRIK12½½
PLANTE½21½

Caractéristiques des pokemons à instancier

pikachu    Bulbizarre    salameche    carapuce

l'algorithme du programme principal sera le suivant :

Instancier les objets pikachu, bulbizarre,salameche et carapuce
carapuce boit une potion de 10 PV
carapuce attaque pikachu
si pikachu est vivant alors
    pikachu attaque carapuce
salameche attaque bulbizarre
si bulbizarre est vivant alors
    bulbizarre attaque salameche
bulbizarre boit une potion de 10 PV



résultat souhaité

carapuce boit une potion de 10 PV
carapuce a 50 PV
carapuce attaque Pikachu
carapuce inflige 20 dégâts à Pikachu
il reste 40 PV à Pikachu
Pikachu attaque carapuce
Pikachu inflige 50 dégâts à carapuce
carapuce est KO
il reste 0 PV à carapuce
salameche attaque Bulbizarre
salameche inflige 40 dégâts à Bulbizarre
il reste 5 PV à Bulbizarre
Bulbizarre attaque salameche
Bulbizarre inflige 10.0 dégâts à salameche
il reste 50.0 PV à salameche
Bulbizarre boit une potion de 10 PV
Bulbizarre a 15 PV

Exercice 7.4 : Cryptage selon le « Code de César »

Consignes:

Exercice à faire comme s'il s'agisissait d'une épreuve écrite

N'utilisez l'ordinateur que pour compléter les champs.

Dans cet exercice, on étudie une méthode de chiffrement de chaînes de caractères alphabétiques. Pour des raisons historiques, cette méthode de chiffrement est appelée "code de César". On considère que les messages ne contiennent que les lettres capitales de l’alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZ" et la méthode de chiffrement utilise un nombre entier fixé appelé la clé de chiffrement.

1. Soit la classe CodeCesar définie ci-dessous :

On rappelle que la méthode str.find(lettre) renvoie l'indice (index) de la lettre dans la chaîne de caractères str

Représenter le résultat d’exécution du code Python suivant :

    code1 = CodeCesar(3)
    print(code1.decale('A'))
    print(code1.decale('X'))

2. La méthode de chiffrement du « code César » consiste à décaler les lettres du message dans l’alphabet d'un nombre de rangs fixé par la clé. Par exemple, avec la clé 3, toutes les lettres sont décalées de 3 rangs vers la droite : le A devient le D, le B devient le E, etc.

Ajouter une méthode cryptage(self, texte) dans la classe CodeCesar définie à la question précédente, qui reçoit en paramètre une chaîne de caractères (le message à crypter) et qui retourne une chaîne de caractères (le message crypté).

Cette méthode cryptage(self, texte) doit crypter la chaîne texte avec la clé de l'objet de la classe CodeCesar qui a été instancié.

Exemple :

>>> code1 = CodeCesar(3)
>>> code1.cryptage("NSI")
'QVL'

3. Ecrire un programme qui :

  • demande de saisir la clé de chiffrement
  • crée un objet de classe CodeCesar
  • demande de saisir le texte à chiffrer
  • affiche le texte chiffré en appelant la méthode cryptage

4. On ajoute la méthode transforme(texte) à la classe CodeCesar :

On exécute la ligne suivante : print(CodeCesar(10).transforme("PSX"))

Que va-t-il s’afficher ? Expliquer votre réponse.

Exercice 7.5 : Classe élève

Créer une classe Eleve dont les attributs sont : nom (str), prenom (str) et matieres (un dictionnaire dont les clés sont les matières dont les valeurs une liste de notes)

Créer la méthode constructeur qui prend en paramètres lui-même, le nom de l'élève, le prénom de l'élève et une liste de matières (on se limitera à 3 matières)

Pour chaque matières de la liste matieres passée en paramètres par exemple ['Maths','NSI','Philo'], il faut créer l'attribut matières pour que le dictionnaire self.matieres={'Maths':[],'NSI':[],'Philo":[]}

Créer l'objet, votre login réseau dont les attributs seront vos nom et prenom et vos matières

Créer la méthode Ajoute_note prenant en paramètre la matière et la note, qui ajoutera une note dans le dictionnaire matieres de la matière passée en paramètre

Créer une méthode Moyenne qui prend en paramètre la matière qui reverra la moyenne de cette matière




Fond :  Texte :  Tables :  Thème du langage: