Ce guide couvre la programmation orientée objet (POO) en Python et les gestionnaires de contexte, avec des exemples pratiques de capture de stdout/stderr et l’utilisation du patron Tee pour afficher et capturer la sortie simultanément.
1. Classes en Python
Les classes sont un mécanisme clé de la POO. Une classe est un modèle pour créer des objets avec des attributs (données) et des méthodes (fonctions). Les objets créés à partir d’une classe sont appelés instances. Les classes permettent de structurer le code, améliorer sa réutilisation et faciliter la maintenance.
Structure d’une classe
class ClassName:
def __init__(self, param1, param2):
self.param1 = param1
self.param2 = param2
def method(self):
return f'{self.param1} et {self.param2}'
Points clés :
__init__: constructeur pour initialiser les attributs de l’objet.self: référence à l’instance courante.- Attributs : définis via
self, accessibles dans toutes les méthodes. - Méthodes : manipulent les données de l’objet.
Création d’objets
class Car:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
def description(self):
return f'{self.year} {self.make} {self.model}'
my_car = Car('Toyota', 'Corolla', 2020)
print(my_car.description()) # Sortie: 2020 Toyota Corolla
Types de méthodes
- Méthodes d’instance — fonctionnent sur les objets (
self). - Méthodes de classe — fonctionnent sur la classe (
cls) via@classmethod. - Méthodes statiques — indépendantes de l’instance et de la classe (
@staticmethod).
Héritage
class Animal:
def speak(self):
return 'Son animal'
class Dog(Animal):
def speak(self):
return 'Ouaf'
Polymorphisme
class Cat(Animal):
def speak(self):
return 'Miaou'
cat = Cat()
print(cat.speak()) # Sortie: Miaou
- La même méthode fonctionne différemment selon le type d’objet.
Encapsulation
class Car:
def __init__(self, make, model):
self._make = make # Attribut protégé
self._model = model
def get_make(self):
return self._make
def set_make(self, make):
self._make = make
Méthodes magiques et destructeur
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f'Point({self.x}, {self.y})'
p = Point(3, 4)
print(p) # Sortie: Point(3, 4)
Diagramme ASCII : Héritage et Polymorphisme
┌─────────┐
│ Animal │
└─────────┘
│ speak() │
└─────────┘
▲
┌───────┴────────┐
│ │
┌─────────┐ ┌─────────┐
│ Dog │ │ Cat │
└─────────┘ └─────────┘
│ speak() │ │ speak() │
└─────────┘ └─────────┘
2. Gestionnaires de Contexte en Python
Les gestionnaires de contexte permettent d’allouer et de libérer automatiquement des ressources, garantissant un nettoyage correct même en cas d’erreurs.
Utilisation de @contextmanager
from contextlib import contextmanager
@contextmanager
def my_context():
print("Entrée dans le contexte")
try:
yield "Ressource"
finally:
print("Sortie du contexte")
Usage :
with my_context() as res:
print("Dans le contexte :", res)
Capture de stdout/stderr et Tee
Python permet de capturer stdout, stderr ou les deux, et de montrer et capturer simultanément avec le patron Tee.
3. Exemple complet : oop_and_context.py
"""
oop_and_context.py
Exemples de classes, principes POO et gestionnaires de contexte en Python.
Inclut :
- Définition de classes, héritage, polymorphisme, encapsulation
- Méthodes d’instance, de classe et statiques
- Méthodes magiques et destructeur
- Gestionnaires de contexte avec @contextmanager
- Capture de stdout, stderr et capture combinée
- Patron Tee : sortie visible et capture simultanée
- Gestionnaire de contexte basé sur une classe
"""
import sys
import io
from contextlib import contextmanager
# ==========================
# Partie 1 : Classes et POO
# ==========================
class Animal:
"""Classe de base pour les animaux."""
def speak(self):
return 'Son animal'
class Dog(Animal):
def speak(self):
return 'Ouaf'
class Cat(Animal):
def speak(self):
return 'Miaou'
class Car:
"""Exemple de classe avec encapsulation."""
def __init__(self, make, model, year=None):
self._make = make
self._model = model
self.year = year
def get_make(self):
return self._make
def set_make(self, make):
self._make = make
def description(self):
if self.year:
return f'{self.year} {self._make} {self._model}'
return f'{self._make} {self._model}'
class Point:
"""Classe avec méthodes magiques."""
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f'Point({self.x}, {self.y})'
# ==========================
# Partie 2 : Gestionnaires de contexte
# ==========================
@contextmanager
def my_context():
print("Entrée dans le contexte")
try:
yield "Ressource"
finally:
print("Sortie du contexte")
@contextmanager
def capture_stdout():
old_stdout = sys.stdout
sys.stdout = buffer = io.StringIO()
try:
yield buffer
finally:
sys.stdout = old_stdout
@contextmanager
def capture_stderr():
old_stderr = sys.stderr
sys.stderr = buffer = io.StringIO()
try:
yield buffer
finally:
sys.stderr = old_stderr
@contextmanager
def capture_output():
old_stdout = sys.stdout
old_stderr = sys.stderr
sys.stdout = sys.stderr = buffer = io.StringIO()
try:
yield buffer
finally:
sys.stdout = old_stdout
sys.stderr = old_stderr
class Tee(io.StringIO):
"""Sortie visible et capture simultanée."""
def __init__(self, original):
super().__init__()
self.original = original
def write(self, text):
self.original.write(text)
super().write(text)
def flush(self):
self.original.flush()
@contextmanager
def capture_stdout_tee():
old_stdout = sys.stdout
sys.stdout = tee = Tee(old_stdout)
try:
yield tee
finally:
sys.stdout = old_stdout
# ==========================
# Partie 3 : Gestionnaire de contexte basé sur classe
# ==========================
class OutputCapture:
"""Gestionnaire de contexte basé sur classe pour capturer stdout."""
def __init__(self):
self._buffer = io.StringIO()
self._old_stdout = None
def __enter__(self):
self._old_stdout = sys.stdout
sys.stdout = self._buffer
return self._buffer
def __exit__(self, exc_type, exc_val, exc_tb):
sys.stdout = self._old_stdout
return False # propager les exceptions
# ==========================
# Partie 4 : Démonstrations
# ==========================
def demo_classes():
print("\n--- Démonstration des Classes ---")
dog = Dog()
cat = Cat()
print("Chien dit :", dog.speak())
print("Chat dit :", cat.speak())
my_car = Car('Toyota', 'Corolla', 2020)
print("Description de la voiture :", my_car.description())
my_car.set_make('Honda')
print("Marque mise à jour :", my_car.get_make())
point = Point(3, 4)
print("Point :", point)
def demo_context_managers():
print("\n--- Démonstration des Gestionnaires de Contexte ---")
with my_context() as res:
print
(« Dans le contexte : », res)
with capture_stdout() as out:
print("stdout capturé")
print("Contenu :", out.getvalue().strip())
with capture_stderr() as err:
print("Cela va vers stdout")
sys.stderr.write("Message d'erreur\n")
print("Erreurs :", err.getvalue().strip())
with capture_output() as out_all:
print("Stdout dans capture combinée")
sys.stderr.write("Stderr dans capture combinée\n")
print("Sortie combinée :", out_all.getvalue().strip())
with capture_stdout_tee() as tee_out:
print("Sortie visible ET capturée avec Tee")
print("Buffer Tee :", tee_out.getvalue().strip())
with OutputCapture() as class_capture:
print("Capture utilisant le gestionnaire basé sur classe")
print("Buffer du gestionnaire de classe :", class_capture.getvalue().strip())