Exercice 01 : Un "Pretty Printer" d'Objet avec Introspection
Objectif
Cet exercice a pour but de vous faire utiliser les fonctions d'introspection de base (dir, hasattr, getattr) pour créer une fonction qui peut afficher de manière lisible les attributs et leurs valeurs pour n'importe quel objet.
Contexte
Lorsque vous déboguez, il est souvent utile d'afficher l'état d'un objet. La fonction print() de base sur un objet personnalisé n'est pas très informative (elle affiche quelque chose comme <__main__.MaClasse object at 0x...>).
Vous allez écrire une fonction pretty_print(obj) qui parcourt les attributs d'un objet et les affiche joliment, en ignorant les méthodes et les attributs "magiques" (ceux qui commencent et finissent par __).
Énoncé
-
Créez un nouveau fichier Python nommé
pretty_printer.py. -
Définissez une classe de test
Utilisateur.- Le constructeur
__init__doit prendre unnom, unemailet unage. - La classe doit aussi avoir un attribut de classe, par exemple
domaine = "example.com". - Définissez une méthode simple, par exemple
saluer(), qui retourne une chaîne de caractères.
- Le constructeur
-
Définissez la fonction
pretty_print(obj).- Elle prend un objet
objen argument. - Commencez par afficher le nom de la classe de l'objet. Vous pouvez l'obtenir avec
obj.__class__.__name__. - Utilisez
dir(obj)pour obtenir la liste de tous les attributs et méthodes. - Itérez sur chaque
nom_attributdans la liste retournée pardir(). - Pour chaque
nom_attribut, vous devez filtrer pour ne garder que les attributs "publics" :- Ignorez les attributs qui commencent par un underscore
_. C'est une manière simple d'ignorer les attributs "magiques" (__...__) et "protégés" (_...). - Récupérez la valeur de l'attribut en utilisant
getattr(obj, nom_attribut). - Vérifiez que l'attribut n'est pas une méthode. Une manière simple de le faire est de vérifier que la valeur n'est pas "appelable" (callable) avec la fonction
callable().
- Ignorez les attributs qui commencent par un underscore
- Si un attribut passe tous ces filtres, affichez son nom et sa valeur dans un format lisible, par exemple
- nom : valeur.
- Elle prend un objet
-
Testez votre fonction.
- Dans le bloc
if __name__ == '__main__':, créez une instance de votre classeUtilisateur. - Appelez
pretty_print()avec cette instance. - Pour montrer que votre fonction est générique, appelez-la aussi avec un autre type d'objet, par exemple une simple instance de
objectà laquelle vous avez ajouté des attributs dynamiquement.
- Dans le bloc
Résultat Attendu
L'exécution de votre script doit produire une sortie claire et formatée qui liste uniquement les attributs de données publics de l'objet, en ignorant les méthodes et les attributs spéciaux.
--- Affichage de l'objet Utilisateur ---
Classe: Utilisateur
- age : 30
- domaine : example.com
- email : alice@email.com
- nom : Alice
--- Affichage de l'objet générique ---
Classe: object
- couleur : bleu
- valeur : 123
Cliquez ici pour voir un exemple de code de solution
# pretty_printer.py
def pretty_print(obj):
"""
Affiche les attributs de données publics d'un objet de manière lisible,
en utilisant l'introspection.
"""
if obj is None:
print("Objet est None")
return
# Affiche le nom de la classe de l'objet
print(f"Classe: {obj.__class__.__name__}")
# Parcourt tous les noms d'attributs et de méthodes
for attr_name in dir(obj):
# Filtre 1: Ignorer les attributs qui commencent par '_'
if not attr_name.startswith('_'):
# Récupère la valeur de l'attribut
try:
attr_value = getattr(obj, attr_name)
except AttributeError:
continue # Peut arriver dans des cas complexes
# Filtre 2: Ignorer les méthodes (ou tout ce qui est appelable)
if not callable(attr_value):
print(f" - {attr_name} : {attr_value}")
# --- Classe de test ---
class Utilisateur:
"""Une classe simple pour les tests."""
domaine = "example.com"
def __init__(self, nom: str, email: str, age: int):
self.nom = nom
self.email = email
self.age = age
self._secret = "ceci est un secret" # Attribut protégé, doit être ignoré
def saluer(self):
"""Une méthode simple, doit être ignorée."""
return f"Bonjour, je suis {self.nom}."
# --- Tests ---
if __name__ == "__main__":
# 1. Test avec un objet de notre classe Utilisateur
user = Utilisateur(nom="Alice", email="alice@email.com", age=30)
print("--- Affichage de l'objet Utilisateur ---")
pretty_print(user)
print("\n" + "="*20 + "\n")
# 2. Test avec un objet générique
generic_obj = object()
# Ajout d'attributs dynamiques
setattr(generic_obj, 'valeur', 123)
setattr(generic_obj, 'couleur', 'bleu')
print("--- Affichage de l'objet générique ---")
pretty_print(generic_obj)