{{ :suivant.png?nolink&30|}} {{ :retour.png?nolink&30|}} [[:python:accueilpython|{{ :iconemaison.jpg?nolink&30|Sommaire Python et microPython}}]]
===== Programmation Orientée Objet (illustrée en Python & C#) =====
[Mise à jour le : 4/7/2023]
{{ :python:poo:objectorientedprogramming-horizontal.jpg?nolink|}}
* **Sources**
* **Documentation** sur Python.org : fonctions natives (built-in)
* **Outils**
* IDE : Visual Studio
* UML for Python : pynsource
* **Lectures connexes**
* **Real Python**
* Object-Oriented Programming (OOP) With Python
* **Mots-clés** : objet, état, comportement, instance de classe, classe, attribut, constructeur, méthode, méthode spéciale, propriété, association, héritage, polymorphisme.
OBJET = ÉTAT + COMPORTEMENTS
//Exemple// \\ Pour décrire la voiture ci-dessus sous la forme d'un objet logiciel (très simplifié), on peut : \\ - la **nommer** maRenaultClio, \\ - préciser son **état** par "couleur <- rouge", "année <- 2019", vitesse <- 30 etc, \\ - lui affecter les **comportements** "avancer", "reculer", etc.
class nomClass:
''' docstring'''
pass # Évite qu'une erreur ne se produise lorsque la classe est vide
//Exemple// \\
Création d'une classe “Monstre” vide !
{{ :python:poo:monstrevide.png?nolink|Réalisé avec PynSource}}
class Monstre:
pass # classe sans attributs ni méthodes
class nomClass {
// corps de la classe
}
//Exemple// \\
Création d'une classe “Monstre” vide !
{{ :python:poo:vsclasse0.png?nolink|Réalisé avec Visual Studio}}
class Monstre {
}
def __init__(self,argument_1,...,argument_n): # __init__ est ce qui se rapproche le plus d'un constructeur
self.__attribut_1 = argument_1 # ou self.attribut_1 pour que attribut_1 soit public
...
self.__attribut_n = argument_n # ou self.attribut_n pour que attribut_n soit public
{{ :python:poo:monstre2constructeur.png?nolink|Réalisé avec Pynsource}}
//Exemple// \\
Création d'une classe "Monstre" contenant trois attributs, la position du monstre en x et y sur l'écran et son nombre de points de vie (pointsDeVie).
class Monstre:
def __init__(self, nom, x=0, y=0, pv=100):
self.__nom = nom
self.__pointsDeVie = pv
self.__pos_x = x
self.__pos_y = y
class nomClasse {
private type nomAttribut_1; # le mot private est optionnel
...
private type nomAttribut_n;
}
//Exemple// \\
Création d'une classe “Monstre” contenant trois attributs, la position du monstre en x et y sur l'écran et son nombre de points de vie (pointsDeVie).
{{ :python:poo:vsclasse1.png?nolink|Réalisé avec Visual Studio}}
class Monstre
{
private int nom;
private int pointsDeVie;
private int pos_x; // position du monstre en (x,y)
private int pos_y;
}
class Monstre
__nombreDeMonstres = 0 # Cet attribut est statique car non précédé de self.
private static int nombreDeMonstres = 0;
def __init__(self,argument_1,...,argument_n): # __init__ est ce qui se rapproche le plus d'un constructeur
self.__attribut_1 = argument_1 # ou self.attribut_1 pour que attribut_1 soit public
...
self.__attribut_n = argument_n # ou self.attribut_n pour que attribut_n soit public
{{ :python:poo:monstre2constructeur.png?nolink|Réalisé avec Pynsource}}
//Exemple// \\
Création d'une classe "Monstre" contenant trois attributs, la position du monstre en x et y sur l'écran et son nombre de points de vie (pointsDeVie).
class Monstre: # Remarque : la classe est déclarée 1 fois
def __init__(self, nom, x=0, y=0, pv=100):
self.__nom = nom
self.__pointsDeVie = pv
self.__pos_x = x # ou self.pos_x pour que pos_x soit publique
self.__pos_y = y
== 1.3.2 Méthode d'instance ==
// Mot-clé// \\
Les méthodes d'instance étant des **routines membres de classe**, elles sont définies par le mot-clé **//def//**.
//Syntaxe//
class nomClass:
def nomMethode_1(self,argument_1,...,argument_n):
pass # Évite qu'une erreur ne se produise lorsque la méthode est vide
//Exemple// \\
Création d'une classe “Monstre” contenant trois attributs (+ le constructeur) et trois méthodes.
{{ :python:poo:monstre2.png?nolink|Réalisé avec PynSource}}
class Monstre:
# Les attributs est la méthode __init__ ont été présentées ci-dessus.
def seDeplace(self, x, y):
self.__pos_x = x
self.__pos_y = y
def estTouche(self, degats):
self.__pointsDeVie -= degats
def __str__(self): # Redéfinition de la méthode print
return str(self.__nom) + ' : pos_x=' + str(self.__pos_x) + ' pos_y=' + str(self.__pos_y)+' points de vie=' + str(self.__pointsDeVie)
@staticmethod
def nomMethode(argument_1,...,argument_n):
pass # Évite qu'une erreur ne se produise lorsque la méthode est vide
//Exemple// \\
Création d'une méthode statique getNombreDeMonstresEnVie() dans la classe Monstre pour connaître le nombre de monstres en vie.
{{ :python:poo:monstre2static.png?nolink|Réalisé avec PynSource}}
class Monstre:
__nombreDeMonstres = 0 # Attribut statique
# Modification du constructeur pour incrémenter __nombreDeMonstres
def __init__(self, nom, x=0, y=0, pv=100):
self.__nom = nom
self.__pointsDeVie = pv # exemple self.__posx
self.__pos_x = x # Un attributs (où variable d'instance)
self.__pos_y = y # est rendu privé par : __
Monstre.__nombreDeMonstres += 1
@staticmethod
def getNombreDeMonstresEnVie():
print(f"Le nombre de Monstres en vie est :{Monstre.__nombreDeMonstres}")
# Les autres méthodes ont été présentées précédemment.
class nomClass {
public nomClasse(parametre_1,...,parametre_n) {
private Attribut_1 = parametre_1;
...
private Attribut_n = parametre_n;
}
}
//Exemple// \\
Constructeurs de la classe “Monstre” contenant trois attributs, la position du monstre en x et y sur l'écran et son nombre de points de vie (pointsDeVie).
{{ :python:poo:vsclasse2.png?nolink|Réalisé avec Visual Studio}}
class Monstre {
private string nom;
private int pointsDeVie;
private int pos_x; // position du monstre en (x,y)
private int pos_y;
// Constructeur surchargé
public Monstre(string lenom)
{
nom = lenom;
pos_x = 0;
pos_y = 0;
pointsDeVie = 100;
}
public Monstre(string lenom, int x=0, int y=0, int pv = 100)
{
nom = lenom;
pos_x = x;
pos_y = y;
pointsDeVie = pv;
}
}
class nomClass {
public(ou private) type nomMethode(parametre_1,...,parametre_n) {
// Corps de la méthode d'instance
}
}
//Exemple// \\
Création d'une classe “Monstre” contenant trois attributs (+ le constructeur surchargé) et trois méthodes.
{{ :python:poo:vsclasse3.png?nolink|Réalisé avec Visual Studio}}
class Monstre {
// Les attributs est le constructeur ont été présentés ci-dessus.
public void SeDeplace(int x, int y)
{
pos_x = x;
pos_y = y;
}
public void EstTouche(int degats)
{
pointsDeVie -= degats;
}
public void Affiche()
{
Console.WriteLine($"{nom} : x={pos_x}, y={pos_y}, points de vie={pointsDeVie}");
}
}
== 1.3.3 Méthode de classe (ou statique) ==
//Mot-clé// \\
Une méthode de classe est créée avec le mot-clé **static**.
//Syntaxe//
class nomClass {
public(ou private) static type nomMethode(parametre_1,...,parametre_n) {
// Corps de la méthode de classe
}
}
//Exemple// \\
Création d'une méthode statique getNombreDeMonstresEnVie() dans la classe Monstre pour connaître le nombre de monstres en vie. \\ \\
{{ :python:poo:vsclasse4.png?nolink|Réalisé avec Visual Studio}}
class Monstre {
private string nom;
private int pointsDeVie;
private int pos_x; // position du monstre en (x,y)
private int pos_y;
private static int nombreDeMonstres = 0;
public static void getNombreDeMonstresEnVie()
{
Console.WriteLine($"Nombre de monstres en vie : {Monstre.nombreDeMonstres}");
}
public Monstre(string lenom)
{
nom = lenom;
pos_x = 0;
pos_y = 0;
pointsDeVie = 100;
Monstre.nombreDeMonstres += 1;
}
public Monstre(string lenom, int x=0, int y=0, int pv = 100)
{
nom = lenom;
pos_x = x;
pos_y = y;
pointsDeVie = pv;
Monstre.nombreDeMonstres += 1;
}
// Les autres méthodes ont été présentées ci-dessus.
}
nomObjet = nomClasse(paramètre_1, ...,paramètre_n)
{{ :python:poo:dracula.png?nolink&100|}}
//Exemple//
# Simplification de la classe Monstre vue précédemment
# Limitée à trois attributs publics
class Monstre:
def __init__(self, x=0, y=0, pv=100):
self.pos_x = x
self.pos_y = y
self.pointsDeVie = pv
# Création de l'objet de type
dracula = Monstre(10,10,200)
//Illustration//
{{ :python:poo:poodracula3.png?nolink |Etat de l'objet de la classe Monstre}}
nomClasse nomObjet = nomClasse(paramètre_1, ...,paramètre_n)
{{ :python:poo:dracula.png?nolink&100|Réalisé avec Visual Studio}}
//Exemple// \\
// Simplification de la classe Monstre vue précédemment
class Monstre
{
private int pointsDeVie;
private int pos_x; // position du monstre en (x,y)
private int pos_y;
public Monstre(int x=0, int y=0, int pv = 100)
{
pos_x = x;
pos_y = y;
pointsDeVie = pv;
}
}
public class Jeu
{
public static void Main()
{
Monstre dracula = new Monstre(10,10,200); // Création de l'objet de type
}
}
//Illustration//
{{ :python:poo:draculavs.jpg?nolink |Etat de l'objet de la classe Monstre}}
nomObjet.nomMethode(paramètre_1, ...,paramètre_n)
//Exemple// \\
class Monstre:
def __init__(self, x=0, y=0, pv=100):
self.__pos_x = x
self.__pos_y = y
self.__pointsDeVie = pv
def seDeplace(self, x, y):
self.__pos_x = x
self.__pos_y = y
def estTouche(self, degats):
self.__pointsDeVie -= degats
def __str__(self): # Redéfinition de la méthode print
return 'pos_x=' + str(self.__pos_x) + ' pos_y=' + str(self.__pos_y)+' points de vie=' + str(self.__pointsDeVie)
# Jeu
dracula = Monstre(10, 10, 200)
dracula.seDeplace(20, 30)
dracula.estTouche(6)
print(f'Dracula est touché : {dracula}') # Résultat - Dracula est touché : posx=20 posy=30 points de vie=194
// Illustration// \\ Objet dracula après l'exécution de : dracula.seDeplace(20, 30)
{{ :python:poo:poodracula4.png?nolink |Etat de l'objet de la classe Monstre}}
nomObjet.nomMethode(paramètre_1, ...,paramètre_n)
//Exemple// \\
class Monstre
{
private int pointsDeVie;
private int pos_x; // position du monstre en (x,y)
private int pos_y;
public Monstre(int x = 0, int y = 0, int pv = 100)
{
pos_x = x;
pos_y = y;
pointsDeVie = pv;
}
public void SeDeplace(int x, int y)
{
pos_x = x;
pos_y = y;
}
public void EstTouche(int degats)
{
pointsDeVie -= degats;
}
public void Affiche()
{
Console.WriteLine($"x={pos_x}, y={pos_y}, points de vie={pointsDeVie}");
}
}
public class Jeu
{
public static void Main()
{
Monstre dracula = new Monstre(10,10,200);
dracula.SeDeplace(20, 30);
dracula.EstTouche(6);
Console.Write("Dracula est touché ");
dracula.Affiche(); // Résultat - Dracula est touché x=20, y=30, points de vie=194
}
}
// Illustration// \\ Objet dracula après l'exécution de : dracula.SeDeplace(20, 30)
{{ :python:poo:draculavs1.jpg?nolink |}}
class Monstre: # Simplifiée
def __init__(self, x=0, y=0, pv=100):
self.__pos_x = x # Les attributs (où variables d'instances)
self.__pos_y = y # sont rendus privés lorsqu'ils sont précédés de __
self.__pointsDeVie = pv
def getpos_x(self): # Accesseur (getteur)
return self.__pos_x
def getpos_y(self): # Accesseur (getteur)
return self.__pos_y
def getpointsDeVie(self): # Accesseur (getteur)
return self.__pointsVie
def seDeplace(self, x, y):
self.__pos_x = x
self.__pos_y = y
def estTouche(self, degats):
self.__pointsDeVie -= degats
def __str__(self): # Redéfinition de la méthode print
return 'posx=' + str(self.__pos_x) + ' posy=' + str(self.__pos_y)+' points de vie=' + str(self.__pointsDeVie)
* **Accesseur (getteur)**
Les méthodes //getpos_x()//, //getpos_y()//, //getpointVie()// sont appelées **accesseurs** ou getteur. Elles exposent les attributs privés de l'objet. Il s'agit de fonction permettant de consulter la valeur des attributs de l'objet. Le nom de ces fonctions commence par get.
* **Mutateur (setteur)**
Pour accéder aux attributs privés de l'objet dans le but de les modifier, on construit des **mutateurs** ou setteurs.
//Exemple// \\
Mutateur accédant aux points de vie dans la classe Monstre.
# A ajouter dans la classe Monstre
def setpointsDeVie(self, pv): # Mutateur (setter)
self.__pointsDeVie = pv
# Accès à l'attribut __pointsVie
dracula.setpointsDeVie(400)
public type NomPropriete { get; set; }
//Exemple// \\
Les attributs de la classe “Monstre” sont masqués. Pour y accéder sans passer par les méthodes de l'objet, on définit les **propriétés** //Pos_x//, //Pos_y// et //PointDeVie//.
{{ :python:poo:vsclasse5.png?nolink|Réalisé avec Visual Studio}}
class Monstre
{
private int pointsDeVie;
private int pos_x; // position du monstre en (x,y)
private int pos_y;
public int Pos_x
{
get { return pos_x; }
}
public int Pos_y
{
get { return pos_y; }
}
public int PointDeVie
{
get { return pointsDeVie; }
set { pointsDeVie = value; }
}
public void SeDeplace(int x, int y)
{
pos_x = x;
pos_y = y;
}
public void EstTouche(int degats)
{
pointsDeVie -= degats;
}
public void Affiche()
{
Console.WriteLine($"{nom} : x={pos_x}, y={pos_y}, points de vie={pointsDeVie}");
}
}
class O2:
def jeTravaillePourO2(self):
print("Je travaille pour O2")
class O1:
# lien d'association de O1 --> O2
def __init__(self, O2):
self.__lienO2 = O2
def jeTravaillePourO1(self):
print("Je travaille pour O1 et demande à O2 de travailler")
self.__lienO2.jeTravaillePourO2()
# Programme
objO2 = O2()
objO1 = O1(objO2)
objO1.jeTravaillePourO1()
//Résultat// \\
Je travaille pour O1 et demande à O2 de travailler \\
Je travaille pour O2 \\ \\
class O1
{
// Champs
private O2 lienO2; // Lien d'association (fort et permanent) avec un objet O2
// Constructeur
public O1(O2 objO2) // Passage de l'objet O2 à lier avec l'objet O1
{
lienO2 = objO2;
}
// Méthode d'instance
public void jeTravaillePourO1()
{
Console.WriteLine("Je travaille pour O1 et demande à O2 de travailler");
lienO2.jeTravaillePourO2();
}
}
class O2
{
public void jeTravaillePourO2()
{
Console.WriteLine("Je travaille pour O2");
}
}
public class Program
{
public static void Main()
{
O2 objO2 = new O2(); // Création de l'objet O2
O1 objO1 = new O1(objO2); // Création de l'objet O1 initialisé avec O2
objO1.jeTravaillePourO1(); // L'objet O1 envoie un message à l'objet O2
}
//Résultat// \\
Je travaille pour O1 et demande à O2 de travailler \\
Je travaille pour O2
class Estomac:
pass
class Monstre:
def __init__(self, nom, x=0, y=0, pv=100):
self.__nom = nom
self.__pos_x = x # Un attributs (où variable d'instance)
self.__pos_y = y # est rendu privé par : __
self.__pointsDeVie = pv # exemple self.__posx
self.__estomac = Estomac()
Monstre.__nombreDeMonstres += 1
# Programme
dracula = Monstre("Dracula", verreDeSang)
namespace Enfer
{
class Estomac {// On définira ici les particularité de l'estomac}
class Monstre {
private Estomac estomac;
public Monstre(string lenom, int x = 0, int y = 0, int pv = 100) {
// ...
estomac = new Estomac(); // Chaque monstre possède un estomac
// ... // Si le montre disparaît, l'estomac aussi
}
}
//...
public class Program
public static void Main() {
Monstre dracula = new Monstre("Dracula", 10, 10, 200);
}
}
}
class Verre:
def __init__(self, vol):
self.__volume = vol
def remplit(self, vol):
self.__volume += vol
def vide(self, vol):
self.__volume = self.__volume - vol
def getvolume(self): # Accesseur (getteur)
return self.__volume
class Monstre:
# Le code est limité à l'ajout de la méthode boit dans la version précédente
# Ici le lien d'association est faible et provisoire verre n'existe plus à la sortie de la méthode boit
def boit(self, vol, verre):
verre.vide(vol)
# Programme
# Un vampire sert un verre de sang à Dracula
verreDeSang = Verre(50)
print(f'Le verre contient {verreDeSang.getvolume()} cl de sang') # 1
dracula = Monstre("Dracula", verreDeSang)
# Dracula voit le verre et se déplace
dracula.seDeplace(20, 30)
# mais reçoit un projectile
dracula.estTouche(6)
print(f'{dracula} : touché !') # 2
Monstre.getNombreDeMonstresEnVie() # 3
# Toujours en vie il boit
dracula.boit(10, verreDeSang)
print(f'Il reste {verreDeSang.getvolume()} cl dans le verre de sang') #4
//Résultat// \\
1. Le verre contient 50 cl de sang \\
2. Dracula : pos_x=20 pos_y=30 points de vie=94 : touché ! \\
3. Le nombre de monstres en vie est : 1 \\
4. Il reste 40 cl dans le verre de sang
namespace Enfer
{
class Verre
{
private int volume;
public Verre(int vol) { volume = vol; }
public void Remplit(int vol) { volume += vol; }
public void Vide(int vol) { volume -= vol; }
public int Volume { get { return volume; } }
}
class Monstre
{
/*
Le code est limité à l'ajout de la méthode boit dans la version précédente
Ici le lien d'association est faible et provisoire verre n'existe plus à la sortie de la méthode boit
*/
public void boit(int vol, Verre verre)
{
verre.Vide(vol);
}
}
public class Program
{
public static void Main()
{
// Un vampire sert un verre de sang à Dracula
Verre verreDeSang = new Verre(50);
Console.WriteLine($"Le verre contient {verreDeSang.Volume}cl de sang");
Monstre dracula = new Monstre("Dracula", 10, 10, 200);
dracula.Affiche();
// Dracula voit le verre et se déplace
dracula.SeDeplace(20, 30);
// mais reçoit un projectile
dracula.EstTouche(6);
dracula.Affiche("est touché");
// Toujours en vie il boit
dracula.boit(10, verreDeSang);
Console.WriteLine($"Il reste {verreDeSang.Volume}cl dans le verre de sang");
}
}
}
//Résultat// \\
1. Le verre contient 50 cl de sang \\
2. Dracula : pos_x=20 pos_y=30 points de vie=94 : touché ! \\
3. Le nombre de monstres en vie est : 1 \\
4. Il reste 40 cl dans le verre de sang
class nomClasse(nomClasseMère) # nomClasse hérite de nomClasseMère
pass # Évite qu'une erreur ne se produise lorsque la méthode est vide
//Exemple//\\
# Dans l'exemple défini plus haut
# Redéfinition de la méthode str héritée de object
def __str__(self):
return "Elève : " + self.__prenom + " " + self.__nom + " " + str(self.__age) + " " + "ans"
//Exemple//\\