Cours Python · Module 3: Programmation orientée objet
Décorateurs - s'adapter à l'environnement
Dans cette leçon12
Bienvenue dans la dernière leçon du module 3 ! Darwin ici, pour une leçon finale avancée.
Dans la nature, les animaux s'adaptent à leur environnement - les caméléons acquièrent la capacité de changer de couleur, les chauves-souris développent l'écholocation, les oiseaux migrateurs développent une navigation magnétique. En Python, les décorateurs permettent une adaptation similaire - ils modifient le comportement des fonctions et des classes sans changer leur code !
1# Fonction ordinaire
2def observe_species(name):
3 print(f"Observation : {name}")
4
5# Fonction avec décorateur - journalisation automatique !
6@log_observation
7def observe_species(name):
8 print(f"Observation : {name}")Le corps de la fonction n'a pas changé. Une seule ligne, @log_observation, au-dessus de la définition suffit pour que chaque appel soit désormais consigné automatiquement. Tu verras dans un instant comment écrire un tel décorateur.
Que sont les décorateurs ?
Un décorateur est une fonction qui prend une autre fonction (ou classe) et renvoie une version modifiée.
Analogie Safari : c'est comme équiper un chercheur - des jumelles ne changent pas le chercheur, mais elles étendent ses capacités d'observation !
1def my_decorator(func):
2 """Décorateur - prend une fonction, renvoie une version modifiée"""
3 def wrapper():
4 print("Quelque chose avant la fonction")
5 func() # Appelle la fonction d'origine
6 print("Quelque chose après la fonction")
7 return wrapper
8
9@my_decorator
10def say_hello():
11 print("Bonjour !")
12
13say_hello()L'appel say_hello() affiche :
1Quelque chose avant la fonction
2Bonjour !
3Quelque chose après la fonctionLa ligne du milieu vient de la fonction d'origine, les deux autres du wrapper que le décorateur a mis à la place de say_hello.
La syntaxe @decorator est un raccourci pour :
1def say_hello():
2 print("Bonjour !")
3
4say_hello = my_decorator(say_hello) # Décoration manuelleComment fonctionnent les décorateurs ?
Un décorateur est une fonction d'ordre supérieur - une fonction qui opère sur des fonctions !
1def simple_decorator(func):
2 """
3 Décorateur - motif wrapper
4
5 1. Accepte une fonction
6 2. Définit wrapper
7 3. Renvoie wrapper
8 """
9 def wrapper():
10 print(f"[AVANT] Appel de {func.__name__}")
11 result = func()
12 print(f"[APRÈS] Terminé {func.__name__}")
13 return result
14 return wrapper
15
16@simple_decorator
17def greet():
18 print("Bonjour !")
19 return "Terminé"
20
21# greet est maintenant wrapper, pas la fonction d'origine !
22greet()Le programme affiche :
1[AVANT] Appel de greet
2Bonjour !
3[APRÈS] Terminé greetLe wrapper renvoie aussi le résultat de la fonction d'origine (result), donc la valeur "Terminé" ne se perd pas en chemin.
Décorateurs avec arguments de fonction
Pour que le décorateur fonctionne avec des fonctions qui acceptent des arguments, utilise *args et **kwargs :
1def log_decorator(func):
2 def wrapper(*args, **kwargs):
3 """Le wrapper accepte n'importe quels arguments"""
4 print(f"Appel de {func.__name__} avec args={args}, kwargs={kwargs}")
5 result = func(*args, **kwargs)
6 print(f"Résultat : {result}")
7 return result
8 return wrapper
9
10@log_decorator
11def add(a, b):
12 return a + b
13
14@log_decorator
15def greet(name, greeting="Bonjour"):
16 return f"{greeting}, {name} !"
17
18add(5, 3)
19
20greet("Darwin", greeting="Salut")Les deux appels affichent :
1Appel de add avec args=(5, 3), kwargs={}
2Résultat : 8
3Appel de greet avec args=('Darwin',), kwargs={'greeting': 'Salut'}
4Résultat : Salut, Darwin !Le même wrapper a géré une fonction avec deux arguments positionnels et une fonction avec un argument nommé : *args recueille les arguments positionnels et **kwargs les arguments nommés.
functools.wraps - préserver les métadonnées
Problème : le décorateur change le __name__ et le __doc__ de la fonction !
1def my_decorator(func):
2 def wrapper(*args, **kwargs):
3 return func(*args, **kwargs)
4 return wrapper
5
6@my_decorator
7def important_function():
8 """Cette fonction est importante"""
9 pass
10
11print(important_function.__name__) # "wrapper" - faux !
12print(important_function.__doc__) # None - pas de documentation !Solution : utilise @functools.wraps !
1from functools import wraps
2
3def my_decorator(func):
4 @wraps(func) # Préserve les métadonnées de la fonction d'origine
5 def wrapper(*args, **kwargs):
6 return func(*args, **kwargs)
7 return wrapper
8
9@my_decorator
10def important_function():
11 """Cette fonction est importante"""
12 pass
13
14print(important_function.__name__) # "important_function" - correct !
15print(important_function.__doc__) # "Cette fonction est importante" - préservée !IMPORTANT : utilise toujours @wraps(func) dans tes décorateurs !
Décorateurs avec paramètres
Pour qu'un décorateur accepte des paramètres, il faut trois niveaux de fonctions :
1def repeat(times):
2 """Décorateur avec paramètre - répète la fonction N fois"""
3 def decorator(func):
4 @wraps(func)
5 def wrapper(*args, **kwargs):
6 for i in range(times):
7 result = func(*args, **kwargs)
8 return result
9 return wrapper
10 return decorator
11
12@repeat(times=3) # Paramètre du décorateur !
13def say_hello():
14 print("Bonjour !")
15
16say_hello()Un seul appel à say_hello() affiche maintenant Bonjour ! trois fois, car le wrapper exécute la fonction d'origine dans une boucle for autant de fois que la valeur de times.
Structure :
repeat(times)- renvoie le décorateurdecorator(func)- le décorateur proprement ditwrapper(*args, **kwargs)- le wrapper de la fonction
Décorateurs intégrés
Tu connais déjà certains décorateurs intégrés de Python !
@property, @classmethod, @staticmethod
Tu connais les trois depuis les leçons précédentes. Ce sont des décorateurs ordinaires intégrés à Python : chacun change la façon dont on appelle la méthode placée en dessous.
1class Species:
2 def __init__(self, name, population):
3 self._name = name
4 self._population = population
5
6 @property # Getter
7 def name(self):
8 return self._name
9
10 @property
11 def population(self):
12 return self._population
13
14 @population.setter # Setter
15 def population(self, value):
16 if value < 0:
17 raise ValueError("La population ne peut pas être négative")
18 self._population = value
19
20 @classmethod # Méthode de classe
21 def from_dict(cls, data):
22 return cls(data['name'], data['population'])
23
24 @staticmethod # Méthode statique
25 def is_valid_name(name):
26 return len(name) > 0Exemples pratiques de décorateurs
1. Décorateur de chronométrage - mesurer le temps d'exécution
Ce décorateur note l'heure avant et après l'appel et affiche la différence en secondes. La fonction mesurée n'a besoin d'aucune modification :
1import time
2from functools import wraps
3
4def timer(func):
5 """Mesure le temps d'exécution de la fonction"""
6 @wraps(func)
7 def wrapper(*args, **kwargs):
8 start = time.time()
9 result = func(*args, **kwargs)
10 end = time.time()
11 print(f"⏱ {func.__name__} a pris {end - start:.4f}s")
12 return result
13 return wrapper
14
15@timer
16def analyze_dna_sequence(sequence):
17 """Simule une analyse ADN - opération chronophage"""
18 time.sleep(2) # Simulation
19 return f"{len(sequence)} nucléotides analysés"
20
21result = analyze_dna_sequence("ATCGATCG") # ⏱ analyze_dna_sequence a pris 2.0015s2. Décorateur logger - journalisation automatique
Le décorateur de journalisation affiche la date et l'heure, le nom de la fonction et les arguments de chaque appel, puis le résultat ou l'erreur. Il n'avale pas l'exception, il la transmet avec raise :
1from functools import wraps
2from datetime import datetime
3
4def log_calls(func):
5 """Consigne chaque appel de fonction"""
6 @wraps(func)
7 def wrapper(*args, **kwargs):
8 timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
9 print(f"[{timestamp}] Appel : {func.__name__}")
10 print(f" Arguments : args={args}, kwargs={kwargs}")
11
12 try:
13 result = func(*args, **kwargs)
14 print(f" Succès : {result}")
15 return result
16 except Exception as e:
17 print(f" Erreur : {e}")
18 raise
19 return wrapper
20
21@log_calls
22def observe_species(name, location, count):
23 """Enregistre une observation d'espèce"""
24 if count < 0:
25 raise ValueError("Le nombre ne peut pas être négatif")
26 return f"Enregistré : {count}x {name} à {location}"
27
28observe_species("Lion", "Serengeti", 12)La console affiche (avec la date et l'heure du moment) :
1[2024-01-15 14:30:45] Appel : observe_species
2 Arguments : args=('Lion', 'Serengeti', 12), kwargs={}
3 Succès : Enregistré : 12x Lion à SerengetiSi la fonction levait une erreur, par exemple pour un nombre négatif, tu verrais une ligne Erreur au lieu de Succès, et l'exception remonterait jusqu'au code appelant.
3. Décorateur de cache - mémoïsation
Le décorateur de cache mémorise le résultat pour chaque jeu d'arguments. Lors d'un appel suivant avec les mêmes arguments, il renvoie la valeur stockée au lieu de recalculer :
1from functools import wraps
2
3def cache(func):
4 """Met en cache les résultats - ne recalcule pas deux fois la même chose"""
5 cached_results = {}
6
7 @wraps(func)
8 def wrapper(*args):
9 if args in cached_results:
10 print(f"Cache hit pour {args}")
11 return cached_results[args]
12
13 print(f"Calcul pour {args}")
14 result = func(*args)
15 cached_results[args] = result
16 return result
17
18 return wrapper
19
20@cache
21def fibonacci(n):
22 """Calcule le n-ième nombre de Fibonacci"""
23 if n < 2:
24 return n
25 return fibonacci(n - 1) + fibonacci(n - 2)
26
27print(fibonacci(5))Le programme affiche :
1Calcul pour (5,)
2Calcul pour (4,)
3Calcul pour (3,)
4Calcul pour (2,)
5Calcul pour (1,)
6Calcul pour (0,)
7Cache hit pour (1,)
8Cache hit pour (2,)
9Cache hit pour (3,)
105Chaque valeur de 0 à 5 n'est calculée qu'une fois, et les seconds appels pour 1, 2 et 3 prennent le résultat dans le cache. Sans le décorateur, la même fonction s'exécuterait 15 fois, et pour un n plus grand, le nombre d'appels explose.
Remarque : Python a un @functools.lru_cache intégré !
1from functools import lru_cache
2
3@lru_cache(maxsize=128) # Se souvient des 128 derniers résultats
4def fibonacci(n):
5 if n < 2:
6 return n
7 return fibonacci(n - 1) + fibonacci(n - 2)4. Décorateur de contrôle d'accès - autorisation
Ce décorateur prend un paramètre, le code attendu, et vérifie le premier argument de l'appel. La fonction ne reçoit les autres arguments que si le code est correct :
1from functools import wraps
2
3def require_authorization(authorization_code):
4 """Décorateur avec paramètre - nécessite une autorisation"""
5 def decorator(func):
6 @wraps(func)
7 def wrapper(*args, **kwargs):
8 # Vérifie si le premier argument est un code valide
9 if len(args) == 0 or args[0] != authorization_code:
10 raise PermissionError(f"Accès non autorisé à {func.__name__}")
11
12 # Retire le code d'autorisation des arguments
13 return func(*args[1:], **kwargs)
14 return wrapper
15 return decorator
16
17@require_authorization("SAFARI_2024")
18def access_classified_data(species_name):
19 """Accès aux données classifiées - nécessite une autorisation"""
20 return f"Données classifiées sur {species_name} : [CLASSIFIÉ]"
21
22# Autorisation correcte
23print(access_classified_data("SAFARI_2024", "Rhinocéros noir"))
24# "Données classifiées sur Rhinocéros noir : [CLASSIFIÉ]"
25
26# Sans autorisation - erreur !
27try:
28 print(access_classified_data("WRONG_CODE", "Rhinocéros noir"))
29except PermissionError as e:
30 print(f"Erreur : {e}")5. Décorateur de réessai - réessai automatique
La connexion à une station de recherche éloignée coupe parfois. Le décorateur de réessai attrape l'exception, attend un peu et réessaie jusqu'à épuiser le nombre de tentatives :
1from functools import wraps
2import time
3
4def retry(max_attempts=3, delay=1):
5 """Réessaie l'opération en cas d'erreur"""
6 def decorator(func):
7 @wraps(func)
8 def wrapper(*args, **kwargs):
9 for attempt in range(1, max_attempts + 1):
10 try:
11 return func(*args, **kwargs)
12 except Exception as e:
13 print(f"Tentative {attempt}/{max_attempts} échouée : {e}")
14 if attempt < max_attempts:
15 print(f"Nouvel essai dans {delay}s...")
16 time.sleep(delay)
17 else:
18 print("Toutes les tentatives épuisées")
19 raise
20 return wrapper
21 return decorator
22
23@retry(max_attempts=3, delay=0.5)
24def unstable_connection(success_rate=0.3):
25 """Simule une connexion instable"""
26 import random
27 if random.random() > success_rate:
28 raise ConnectionError("Connexion interrompue")
29 return "Succès !"
30
31# Réessaie automatiquement en cas d'erreur
32result = unstable_connection(success_rate=0.8)Empiler plusieurs décorateurs
Les décorateurs peuvent être empilés - appliquer plusieurs à la fois !
1@decorator1
2@decorator2
3@decorator3
4def my_function():
5 passCette écriture équivaut à un emballage manuel : my_function = decorator1(decorator2(decorator3(my_function))). decorator3 est le plus proche de la fonction, c'est donc lui qui l'enveloppe en premier.
L'ordre compte - exécuté de bas en haut !
1from functools import wraps
2
3def bold(func):
4 @wraps(func)
5 def wrapper(*args, **kwargs):
6 return f"**{func(*args, **kwargs)}**"
7 return wrapper
8
9def italic(func):
10 @wraps(func)
11 def wrapper(*args, **kwargs):
12 return f"_{func(*args, **kwargs)}_"
13 return wrapper
14
15@bold
16@italic
17def greet(name):
18 return f"Bonjour, {name}"
19
20print(greet("Darwin")) # "**_Bonjour, Darwin_**"D'abord italic a entouré le résultat de tirets bas, puis bold a ajouté les astérisques. L'ordre d'exécution est greet → italic → bold.
Décorateurs de classe
Les décorateurs peuvent aussi modifier des classes entières !
1def singleton(cls):
2 """Décorateur de classe - motif Singleton"""
3 instances = {}
4
5 @wraps(cls)
6 def get_instance(*args, **kwargs):
7 if cls not in instances:
8 instances[cls] = cls(*args, **kwargs)
9 return instances[cls]
10
11 return get_instance
12
13@singleton
14class DatabaseConnection:
15 def __init__(self, host):
16 self.host = host
17 print(f"Connexion à {host}...")
18
19# Première instance
20db1 = DatabaseConnection("localhost") # Affiche : "Connexion à localhost..."
21
22# « Deuxième » instance - en réalité la même !
23db2 = DatabaseConnection("localhost") # N'affiche rien
24
25print(db1 is db2) # True - le même objet !Exemple Safari - système complet avec décorateurs
Pour finir, une classe d'espèce où cinq décorateurs travaillent ensemble : journalisation et chronométrage des observations, validation de la population, autorisation pour la suppression et cache des calculs.
1from functools import wraps
2from datetime import datetime
3import time
4from typing import Callable, Any
5
6# === DÉCORATEURS ===
7
8def log_observation(func: Callable) -> Callable:
9 """Consigne toutes les observations d'espèces"""
10 @wraps(func)
11 def wrapper(*args, **kwargs):
12 timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
13 print(f"[{timestamp}] Observation : {func.__name__}")
14 result = func(*args, **kwargs)
15 print(f" Enregistré : {result}")
16 return result
17 return wrapper
18
19def measure_time(func: Callable) -> Callable:
20 """Mesure le temps d'exécution de l'opération"""
21 @wraps(func)
22 def wrapper(*args, **kwargs):
23 start = time.time()
24 result = func(*args, **kwargs)
25 elapsed = time.time() - start
26 print(f" ⏱ Temps : {elapsed:.3f}s")
27 return result
28 return wrapper
29
30def validate_population(func: Callable) -> Callable:
31 """Valide les données de population avant l'enregistrement"""
32 @wraps(func)
33 def wrapper(self, population: int, *args, **kwargs):
34 if not isinstance(population, int):
35 raise TypeError("La population doit être un entier")
36 if population < 0:
37 raise ValueError("La population ne peut pas être négative")
38 return func(self, population, *args, **kwargs)
39 return wrapper
40
41def require_auth(authorization_level: str):
42 """Exige un niveau d'autorisation"""
43 def decorator(func: Callable) -> Callable:
44 @wraps(func)
45 def wrapper(self, auth_code: str, *args, **kwargs):
46 if auth_code != f"SAFARI_{authorization_level}":
47 raise PermissionError(
48 f"Niveau requis : {authorization_level}"
49 )
50 return func(self, *args, **kwargs)
51 return wrapper
52 return decorator
53
54def cache_result(func: Callable) -> Callable:
55 """Met en cache les résultats de calcul"""
56 cache = {}
57
58 @wraps(func)
59 def wrapper(*args):
60 if args in cache:
61 print(f" Cache hit")
62 return cache[args]
63
64 result = func(*args)
65 cache[args] = result
66 return result
67
68 return wrapper
69
70# === CLASSE AVEC DÉCORATEURS ===
71
72class Species:
73 """
74 Classe Species avec des décorateurs Safari
75
76 Démonstration : journalisation, chronométrage, validation, autorisation, cache
77 """
78
79 _registry = {}
80
81 def __init__(self, scientific_name: str, common_name: str, population: int):
82 self.scientific_name = scientific_name
83 self.common_name = common_name
84 self._population = population
85 self.observations = []
86
87 Species._registry[scientific_name] = self
88
89 @property
90 def population(self) -> int:
91 """Getter - property ordinaire"""
92 return self._population
93
94 @population.setter
95 @validate_population # Décorateur de validation !
96 def population(self, value: int) -> None:
97 """Setter avec validation automatique"""
98 self._population = value
99
100 @log_observation # Journalisation automatique
101 @measure_time # Mesure du temps
102 def add_observation(self, location: str, count: int, date: str) -> str:
103 """
104 Ajoute une observation - automatiquement consignée et chronométrée
105
106 Décorateurs : @log_observation, @measure_time
107 """
108 time.sleep(0.1) # Simule une opération
109 obs = {
110 "location": location,
111 "count": count,
112 "date": date
113 }
114 self.observations.append(obs)
115 return f"{count}x {self.common_name} à {location}"
116
117 @cache_result # Met en cache les résultats
118 def calculate_biodiversity_score(self) -> float:
119 """
120 Calcule le score de biodiversité - avec cache
121
122 Opération chronophage - le cache fait gagner du temps !
123 """
124 print(f" Calcul du score pour {self.common_name}...")
125 time.sleep(0.5) # Simule des calculs complexes
126
127 total_obs = sum(obs["count"] for obs in self.observations)
128 unique_locations = len(set(obs["location"] for obs in self.observations))
129
130 return (total_obs * unique_locations) / (self.population + 1)
131
132 @require_auth("ADMIN") # Nécessite une autorisation ADMIN
133 def delete_all_observations(self) -> str:
134 """
135 Supprime toutes les observations - nécessite une autorisation ADMIN
136
137 Décorateur : @require_auth("ADMIN")
138 """
139 count = len(self.observations)
140 self.observations.clear()
141 return f"Observations supprimées : {count}"
142
143 @classmethod
144 def get_total_population(cls) -> int:
145 """Population totale de toutes les espèces"""
146 return sum(s.population for s in cls._registry.values())
147
148 @staticmethod
149 @cache_result # Même les méthodes statiques peuvent être mises en cache !
150 def calculate_extinction_risk(population: int, habitat_loss: float) -> str:
151 """
152 Calcule le risque d'extinction - avec cache
153
154 Args:
155 population: Nombre d'individus
156 habitat_loss: Perte d'habitat (0.0-1.0)
157 """
158 print(f" Calcul du risque...")
159 time.sleep(0.3)
160
161 risk_score = (1000 - population) * habitat_loss
162
163 if risk_score > 800:
164 return "Critique"
165 elif risk_score > 500:
166 return "Élevé"
167 elif risk_score > 200:
168 return "Moyen"
169 else:
170 return "Faible"
171
172 def __repr__(self) -> str:
173 return f"Species('{self.common_name}', pop={self.population})"
174
175# === DÉMONSTRATION ===
176
177print("=== SYSTÈME SAFARI AVEC DÉCORATEURS ===\n")
178
179# Création des espèces
180lion = Species("Panthera leo", "Lion", 120)
181rhino = Species("Diceros bicornis", "Rhinocéros", 45)
182
183# 1. Observations - journalisation et chronométrage automatiques
184print("\n1. OBSERVATIONS (avec @log_observation et @measure_time) :")
185lion.add_observation("Serengeti", 12, "2024-01-15")
186lion.add_observation("Masai Mara", 8, "2024-01-16")
187
188# 2. Validation de la population
189print("\n2. VALIDATION (@validate_population) :")
190try:
191 lion.population = -10 # Erreur - négatif !
192except ValueError as e:
193 print(f"Erreur de validation : {e}")
194
195try:
196 lion.population = "cent" # Erreur - pas un int !
197except TypeError as e:
198 print(f"Erreur de type : {e}")
199
200lion.population = 125 # OK
201print(f"Population mise à jour : {lion.population}")
202
203# 3. Cache - score de biodiversité
204print("\n3. CACHE (@cache_result) :")
205print("Premier appel :")
206score1 = lion.calculate_biodiversity_score()
207print(f"Score : {score1:.2f}")
208
209print("\nDeuxième appel (depuis le cache) :")
210score2 = lion.calculate_biodiversity_score()
211print(f"Score : {score2:.2f}")
212
213# 4. Autorisation
214print("\n4. AUTORISATION (@require_auth) :")
215try:
216 lion.delete_all_observations("WRONG_CODE")
217except PermissionError as e:
218 print(f"Accès refusé : {e}")
219
220result = lion.delete_all_observations("SAFARI_ADMIN")
221print(f"{result}")
222
223# 5. Cache dans une méthode statique
224print("\n5. CACHE DANS UNE MÉTHODE STATIQUE :")
225print("Premier appel :")
226risk1 = Species.calculate_extinction_risk(50, 0.8)
227print(f"Risque : {risk1}")
228
229print("\nDeuxième appel (depuis le cache) :")
230risk2 = Species.calculate_extinction_risk(50, 0.8)
231print(f"Risque : {risk2}")
232
233print("\nParamètres différents (nouveau calcul) :")
234risk3 = Species.calculate_extinction_risk(500, 0.3)
235print(f"Risque : {risk3}")Résumé
Dans cette leçon, tu as appris :
- Ce que sont les décorateurs et comment ils fonctionnent
- La syntaxe
@decorator - Créer des décorateurs avec
*argset**kwargs - Utiliser
@functools.wrapspour préserver les métadonnées - Les décorateurs avec paramètres (trois niveaux de fonctions)
- Les décorateurs intégrés (
@property,@classmethod,@staticmethod) - Des exemples concrets : chronométrage, journalisation, cache, autorisation, réessai
- Empiler plusieurs décorateurs
- Les décorateurs de classe
- Un système Safari complet avec décorateurs
Point de contrôle
Avant de passer à la suite :
- Tu comprends comment les décorateurs modifient les fonctions
- Tu sais créer un décorateur simple
- Tu sais quand utiliser
@wraps - Tu comprends les décorateurs avec paramètres
- Tu sais empiler plusieurs décorateurs
Analogie Safari : les décorateurs sont des adaptations évolutives - un caméléon avec des chromatophores, une chauve-souris avec l'écholocation - ils étendent les capacités sans changer la nature fondamentale !
Félicitations ! Tu as terminé le module 3 - Programmation orientée objet ! Tu maîtrises les classes, l'héritage, l'encapsulation, les méthodes magiques, les type hints et les décorateurs. Tu es prêt pour les prochains défis de Python Safari !
Tu as repéré une erreur dans cette leçon ?
Teste tes connaissances
Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.
1. En Python, un décorateur est :
2. Par convention, comment s'appelle le premier paramètre d'une méthode marquée avec @classmethod ?
Voici 2 des 6 questions de cette leçon. Réponds aux autres dans le jeu.
Tâches pratiques dans le jeu
- Tri horizontal
Range les éléments dans le bon ordre :
- Clique dans l'ordre
Clique sur les éléments dans le bon ordre :
- Éditeur de code
Crée une @classmethod from_dict(cls, data) qui crée un Animal à partir d'un dictionnaire avec les clés 'name' et 'species', par ex. Animal.from_dict({'name': 'Simba', 'species': 'Lion'})
- Éditeur de code
Crée une @staticmethod is_dangerous(species) qui renvoie True pour les espèces 'Lion', 'Crocodile' et 'Hippopotame', et False pour les autres
- Tri horizontal
Range l'en-tête de la méthode de classe from_dict (la ligne sous le décorateur @classmethod) :
- Tri vertical
Range ce qui se passe après l'appel de print(lion) pour un objet doté d'une méthode __str__ :
- Clique dans l'ordre
Clique sur les éléments dans le bon ordre :
- Éditeur de code
Crée les classes : Animal (base), Mammal(Animal), Bird(Animal), Tiger(Mammal), Eagle(Bird)
- Éditeur de code
Dans la classe Animal(name, age, health_status), stocke age et health_status dans des attributs protégés ou privés (self._age ou self.__age) et ajoute les properties age et health_status
- Tri vertical
Range les étapes de création d'une classe enfant :
- Éditeur de code
Crée une classe Zoo avec les méthodes add_animal(animal), remove_animal(name) (supprime l'animal portant ce nom), find_by_species(species) et list_all() (les deux renvoient des listes d'animaux). Les animaux sont des objets Animal(name, species)
- Éditeur de code
Assemble Animal et Zoo dans un programme : crée zoo = Zoo() et, dans une boucle while, lis le choix avec input() : 1 - ajouter (nom, espèce), 2 - supprimer (nom), 3 - chercher par espèce et afficher les noms, 0 - quitter
- Tri vertical
Range les types de méthodes selon leur premier paramètre : d'abord ceux qui reçoivent l'objet (self), puis la classe (cls), et enfin ceux sans self ni cls :