Programmation Orientée Objet en Python

  1. Itnroduction à la Programmation Orientée Objet (POO)

La programmation orientée objet est un paradigme qui utilise des objets et leurs interactions pour concevoir des applications et des programmes informatiques.

1.1 Concepts fondamentaux Classe : Une classe est un modèle ou un plan pour créer des objets. Elle définit des attributs et des méthodes communs à tous les objets de ce type. En Python, on définit une classe avec le mot-clé class, et le nom de la classe suit généralement une convention de PascalCase (première lettre de chaque mot en majuscule).

class Vehicule:  # Définition d'une classe classique
    pass

class Voiture(object):  # Définition d'une classe moderne (hérite de object)
    pass

Objet : Un objet est une instance concrète d'une classe. C'est une entité qui possède des attributs et des méthodes définis par sa classe. Par exemple, si Voiture est une classe, alors maVoiture serait un objet de cette classe.

Instance : Le terme instance est synonyme d'objet. Lorsque nous créons un objet à partir d'une classe, nous disons que nous instancions cette classe.

Attribut : Les attributs sont des variables associées à une classe ou à une instance. On distingue les attributs de classe (communs à toutes les instances) et les attributs d'instance (spécifiques à chaque objet).

Méthode : Une méthode est une fonction définie à l'intérieur d'une classe. Elle représente le comportement ou les fonctionnalités d'un objet.

Constructeur : Le constructeur est une méthode spéciale __init__ qui est appelée automatiquement lors de la création d'un objet. Il est utilisé pour initialiser les attributs de l'objet.

Voici un exemple illustratif :

class Animal:
    def __init__(self, nom, espece):  # Constructeur de la classe
        self.nom = nom  # Attribut d'instance
        self.espece = espece
        self.age = 0  # Attribut d'instance avec valeur par défaut
        
    def crier(self):  # Méthode d'instance
        print(f"{self.nom} émet un son")
        
    def vieillir(self):  # Méthode d'instance
        self.age += 1
        print(f"{self.nom} a maintenant {self.age} an(s)")

# Création d'instances (objets)
chat = Animal("Félix", "Chat")
chien = Animal("Rex", "Chien")

# Utilisation des méthodes
chat.crier()  # Affiche: Félix émet un son
chien.vieillir()  # Affiche: Rex a maintenant 1 an(s)

1.2 Méthodes de classe, méthodes statiques et propriétés

Méthode de classe : Décorée avec @classmethod, une méthode de classe est liée à la classe plutôt qu'à une instance particulière. Elle peut accéder aux attributs de classe mais pas aux attributs d'instance.

class Ecole:
    nombre_eleves = 0  # Attribut de classe
    
    def __init__(self, nom):
        self.nom = nom
        Ecole.nombre_eleves += 1
        
    @classmethod
    def get_nombre_eleves(cls):
        return f"Il y a {cls.nombre_eleves} élèves dans l'école"
    
    @staticmethod
    def verifier_age(age):
        return age >= 18
    
    @property
    def nom_complet(self):
        return f"L'école {self.nom}"

# Utilisation
ecole1 = Ecole("Jean Jaurès")
ecole2 = Ecole("Victor Hugo")

print(Ecole.get_nombre_eleves())  # Méthode de classe
print(Ecole.verifier_age(20))  # Méthode statique
print(ecole1.nom_complet)  # Propriété (pas besoin de parenthèses)

1.3 Héritage

L'héritage permet de créer une nouvelle classe (classe dérivée) qui hérite des attributs et méthodes d'une classe existante (classe de base). La classe dérivée peut étendre ou modifier le comportement hérité.

class Forme:
    def __init__(self, couleur):
        self.couleur = couleur
        
    def afficher_couleur(self):
        print(f"Couleur: {self.couleur}")

class Rectangle(Forme):
    def __init__(self, couleur, largeur, hauteur):
        super().__init__(couleur)  # Appel du constructeur de la classe de base
        self.largeur = largeur
        self.hauteur = hauteur
        
    def calculer_aire(self):
        return self.largeur * self.hauteur
        
    def afficher_couleur(self):  # Redéfinition de la méthode
        super().afficher_couleur()
        print("Je suis un rectangle")

# Utilisation
rectangle = Rectangle("rouge", 5, 3)
rectangle.afficher_couleur()  # Utilise la méthode redéfinie
print(f"Aire: {rectangle.calculer_aire()}")  # Méthode spécifique à Rectangle

1.4 Exemple pratique: Gestion d'une base de données

Voici une classe pour interagir avec une base de données MySQL en utilisant PyMySQL:

import pymysql

class GestionBaseDeDonnees:
    def __init__(self, hote, utilisateur, mot_passe, base, port=3306, charset='utf8'):
        try:
            self.connexion = pymysql.connect(
                host=hote, 
                user=utilisateur, 
                password=mot_passe,
                port=port, 
                charset=charset, 
                db=base,
                autocommit=True
            )
            self.curseur = self.connexion.cursor(cursor=pymysql.cursors.DictCursor)
        except Exception as e:
            print(f"Échec de la connexion à la base de données: {e}")
            
    def executer_requete(self, requete):
        try:
            self.curseur.execute(requete)
            resultat = self.curseur.fetchall()
            return resultat
        except Exception as e:
            print(f"Erreur dans l'exécution de la requête: {e}")
            return None
            
    def __del__(self):
        if hasattr(self, 'curseur'):
            self.curseur.close()
        if hasattr(self, 'connexion'):
            self.connexion.close()
        print("Connexion à la base de données fermée")

# Utilisation
db = GestionBaseDeDonnees('localhost', 'root', 'motdepasse', 'ma_base')
resultats = db.executer_requete('SELECT * FROM utilisateurs;')
if resultats:
    for utilisateur in resultats:
        print(f"ID: {utilisateur['id']}, Nom: {utilisateur['nom']}")

1.5 Exemple pratique: Génération de signature

Voici une approche orientée objet pour générer une signature à partir de données:

import hashlib
from urllib import parse

class GenerateurSignature:
    def __init__(self, donnees_demande):
        self.donnees_demande = donnees_demande
        self.id_fournisseur = self.extraire_id_fournisseur()
        
    def extraire_id_fournisseur(self):
        paires = self.donnees_demande.split('&')
        donnees_dict = {}
        for paire in paires:
            if '=' in paire:
                cle, valeur = paire.split('=', 1)
                donnees_dict[cle] = valeur
        return donnees_dict.get('vendorId', '')
    
    def calculer_md5(self, texte):
        hacheur = hashlib.md5()
        hacheur.update(texte.encode('utf-8'))
        return hacheur.hexdigest()
    
    def generer_signature(self):
        # Premier MD5
        premier_md5 = self.calculer_md5(self.id_fournisseur)
        # Deuxième MD5
        astr = self.calculer_md5(premier_md5)
        # Encodage URL
        url_encode = parse.quote_plus(self.donnees_demande)
        # Signature finale
        chaine_finale = astr + url_encode
        signature = self.calculer_md5(chaine_finale)
        return signature

# Utilisation
donnees = 'vendorId=1697&posCode=pos006&ip=127.0.0.1&posVersion=2.1.1.1.1&mac=;D4-81-D7-CA-20-29;7C-67-A2-9A-06-05;7C-67-A2-9A-06-06;7C-67-A2-9A-06-09;00-00-00-00-00-0000E0'
generateur = GenerateurSignature(donnees)
signature_finale = generateur.generer_signature()
print(f"Signature générée: {signature_finale}")

Cet exemple montre comment encapsuler la logique de génération de signature dans une classe, rendant le code plus modulaire et réutilisable.

Étiquettes: Python POO Programmation orientée objet classes Héritage

Publié le 1 juin à 15h22