Un corrigé pédagogique pour comprendre et justifier vos réponses. Les conseils de rédaction ne constituent pas un barème officiel détaillé.
Application
Croissance des plantes et suppression dans une liste
Des agronomes mesurent chaque jour la hauteur des plantes, la température et l’humidité d’une serre. Chaque Plante possède nom, espece, croissance (durée moyenne en jours), taille (en cm) et exposition (ombre, mi-ombre ou plein soleil). Chaque mesure est un dictionnaire avec plante, jour, hauteur, temperature et humidite. L’objectif est de regrouper les mesures puis de retirer celles prises hors de l’intervalle 20 à 25°C, bornes incluses. Attention : croissance est une durée ; il ne faut pas calculer ici une vitesse en cm par jour.
| Nom | Durée (jours) | Taille (cm) | Exposition |
|---|---|---|---|
| Basilic | 60 | 40 | plein soleil |
| Tomate | 80 | 100 | plein soleil |
| Menthe | 80 | 50 | mi-ombre |
| Tournesol | 85 | 200 | plein soleil |
| Fougère | 90 | 80 | ombre |
Le dossier comporte le sujet et les fichiers listés dans les téléchargements. Les programmes de départ et un aperçu des grands jeux de données sont présentés ci-dessous ; les fichiers complets sont téléchargeables. Travaillez sur une copie. Les appels professeur signalés dans les questions servent à présenter votre démarche ; vous pouvez aussi demander de l’aide en cas de difficulté.
Code fourni : culture.py
#############################################################################
# Jeux de données fournis #
#############################################################################
from plantes import Plante, plantes
from mesures import mesures
#############################################################################
# Écrire le code de la fonction croissance_moyenne de la question 1 #
#############################################################################
def croissance_moyenne(plantes):
pass
#############################################################################
# Écrire le code de la fonction dictionnaire_mesure de la question 2 #
#############################################################################
def dictionnaire_mesure(plantes, mesures):
pass
#############################################################################
# Fonction défaillante à analyser et corriger pour les questions 3 et 4 #
#############################################################################
def purger_mesures_extremes(liste_mesures):
"""
Supprime de la liste toutes les mesures dont la température
n'est pas comprise entre 20 et 25°C inclus.
"""
for mesure in liste_mesures:
if mesure['temperature'] < 20 or mesure['temperature'] > 25:
liste_mesures.remove(mesure)
def test_purger():
mesures_test = [
{'jour': 1, 'plante': 'Basilic', 'temperature': 18.0},
{'jour': 2, 'plante': 'Basilic', 'temperature': 19.0},
{'jour': 3, 'plante': 'Basilic', 'temperature': 22.0},
{'jour': 4, 'plante': 'Basilic', 'temperature': 28.0},
{'jour': 5, 'plante': 'Basilic', 'temperature': 29.0}
]
purger_mesures_extremes(mesures_test)
print("Résultat après la purge :")
for m in mesures_test:
print(f"Jour {m['jour']} : {m['temperature']}°C")
Données fournies : mesures.py
Le fichier mesures.py contient la liste mesures et ses 305 enregistrements. Voici les trois premiers, dans l’ordre du fichier.
jour | plante | hauteur | temperature | humidite |
|---|---|---|---|---|
| 1 | Basilic | 0.85 | 29.3 | 50.89 |
| 1 | Tomate | 1.27 | 21.51 | 47.19 |
| 1 | Menthe | 0.67 | 27.75 | 61.14 |
Pour exécuter le programme sur toutes les données et retrouver les résultats du sujet, utilisez le fichier intégral fourni. Il est aussi inclus dans l’archive ZIP de cette page.
Code fourni : plantes.py
class Plante:
def __init__(self, nom, espece, croissance, taille, exposition):
self.nom = nom
self.espece = espece
self.croissance = croissance # en jours
self.taille = taille # en cm
self.exposition = exposition # type d'exposition
plantes = [
Plante("Basilic", "Ocimum basilicum", 60, 40, "plein soleil"),
Plante("Tomate", "Solanum lycopersicum", 80, 100, "plein soleil"),
Plante("Menthe", "Mentha spicata", 80, 50, "mi-ombre"),
Plante("Tournesol", "Helianthus annuus", 85, 200, "plein soleil"),
Plante("Fougère", "Dryopteris filix-mas", 90, 80, "ombre")
]
Question 1
#Écrire croissance_moyenne(plantes) qui renvoie la moyenne des durées de croissance, ou None si la liste est vide. Écrire au moins deux tests, dont celui de la liste vide.
Indice
Accéder à un attribut avec un point.
Comprendre la correction
def croissance_moyenne(plantes):
if not plantes:
return None
total = 0
for plante in plantes:
total += plante.croissance
return total / len(plantes)On additionne l’attribut croissance de chaque instance. Pour les cinq plantes fournies, (60+80+80+85+90)/5=79 jours. Le contrôle initial empêche la division par zéro.
assert croissance_moyenne([]) is None
assert croissance_moyenne([Plante('A','x',10,20,'ombre'),
Plante('B','x',30,40,'ombre')]) == 20.0
assert croissance_moyenne(plantes) == 79.0Question 2
#Écrire dictionnaire_mesure(plantes, mesures) : chaque clé est le nom d’une plante présente dans plantes, et chaque valeur la liste de ses mesures. Une plante sans mesure doit avoir une liste vide. Concevoir une série de tests pertinente.
PythonUne liste indépendante pour chaque planteÉcrivez votre solution et mettez-la à l’épreuve
Écrivez dictionnaire_mesure(plantes, mesures). Les clés sont tous les noms des objets Plante fournis, même sans relevé. Chaque valeur contient les dictionnaires de mesure complets, dans leur ordre initial. Une mesure d’un nom absent de plantes est ignorée.
def dictionnaire_mesure(plantes, mesures):
# À vous de jouer
pass
Les cas de test proposés :
- Une plante sans relevé : La présence d’une plante ne dépend pas de ses mesures.
- Plusieurs relevés et ordre : Regrouper ne signifie pas trier par jour.
- Listes indépendantes : Deux clés ne doivent pas partager une même liste mutable.
- Nom inconnu : Les clés attendues proviennent du catalogue de plantes.
- Aucune plante : Une collection vide conduit à un dictionnaire vide.
Indice
Les plantes sans relevé doivent exister avant le parcours des mesures.
Comprendre la correction
def dictionnaire_mesure(plantes, mesures):
resultat = {plante.nom: [] for plante in plantes}
for mesure in mesures:
nom = mesure['plante']
if nom in resultat:
resultat[nom].append(mesure)
return resultatOn crée d’abord toutes les clés, avec une liste distincte pour chacune. Ensuite on distribue les mesures. La garde nom in resultat ignore un éventuel nom inconnu, puisque les clés attendues viennent de plantes. Ne pas utiliser dict.fromkeys(noms, []) : toutes les clés partageraient la même liste.
a=Plante('A','x',10,20,'ombre'); b=Plante('B','x',30,40,'ombre')
m1={'plante':'A','jour':1}; m2={'plante':'A','jour':2}
assert dictionnaire_mesure([a,b],[m1,m2]) == {'A':[m1,m2],'B':[]}
assert dictionnaire_mesure([a,b],[]) == {'A':[],'B':[]}
assert dictionnaire_mesure([],[]) == {}Imaginons deux plantes A et B, puis deux relevés pour A. Au départ, le dictionnaire est {'A': [], 'B': []}. Après le premier relevé, seule la liste associée à A contient une mesure ; après le second, elle en contient deux, tandis que B reste présente avec une liste vide. Le point essentiel est l’indépendance des listes. Un test utile consiste à ajouter une mesure au groupe A puis à vérifier que B n’a pas changé. Cela détecte un partage involontaire de la même liste entre toutes les clés.
Question 3
#Exécuter test_purger et analyser purger_mesures_extremes pour identifier l’erreur logique : des températures extrêmes restent après la suppression.
Indice
Suivre simultanément la position courante et le déplacement des cases.
Comprendre la correction
La boucle for avance son indice interne pendant que remove décale les éléments. Avec 18,19,22,28,29, supprimer 18 fait passer 19 à l’indice 0 ; la boucle visite ensuite l’indice 1, donc 22. Elle supprime 28 et saute de la même manière 29. Le résultat fautif est 19,22,29 au lieu de 22. Une suppression peut donc faire sauter l’élément suivant.
Pourquoi une température survit-elle ?Un atelier pour expérimenter
Choisissez une réponse puis confrontez votre intuition à l’explication. Vous pouvez modifier vos choix.
Lire les réponses et leurs explications
- Après suppression de 18 dans [18,19,22], quelle valeur passe à l’indice 0 ?
19. Les éléments se décalent à gauche.
- Que conserve la règle climatique ?
20 et 25. Les deux bornes sont autorisées.
Appuyez votre explication sur les valeurs et les conditions exactes du programme.
Question 4
#Proposer une version corrigée de purger_mesures_extremes qui retire toutes les mesures à température strictement inférieure à 20°C ou strictement supérieure à 25°C.
PythonSupprimer sans sauter la mesure suivanteÉcrivez votre solution et mettez-la à l’épreuve
Corrigez purger_mesures_extremes(liste_mesures). Retirez de la liste reçue les mesures dont temperature est strictement inférieure à 20 ou strictement supérieure à 25. Modifiez cette même liste et conservez l’ordre des mesures restantes ; la fonction ne doit pas renvoyer une liste de remplacement.
def purger_mesures_extremes(liste_mesures):
# À vous de jouer
pass
Les cas de test proposés :
- Deux suppressions consécutives : Le parcours défaillant saute 19 puis 29 après les décalages.
- Les deux bornes sont autorisées : La plage de conservation est fermée aux deux extrémités.
- Tout supprimer : Aucune mesure extrême ne doit survivre.
- Un alias doit voir la purge : Une réaffectation locale ne modifie pas la liste de l’appelant.
- Conserver les données complètes : La purge retire des mesures ; elle ne reconstruit pas des dictionnaires amputés.
- Liste vide : Aucune suppression ni accès hors limites ne doit être tenté.
Comprendre la correction
def purger_mesures_extremes(liste_mesures):
for i in range(len(liste_mesures) - 1, -1, -1):
if not 20 <= liste_mesures[i]['temperature'] <= 25:
liste_mesures.pop(i)Le parcours part de la fin. Supprimer une case ne change alors que les indices déjà visités ; les positions restant à examiner sont intactes. La fonction modifie bien la liste fournie, comme le code initial et son appel le prévoient. Une autre solution correcte est une affectation de tranche liste_mesures[:] = [m for m in liste_mesures if 20<=m["temperature"]<=25] ; une simple réaffectation locale n’aurait pas cet effet sur la liste appelante.
for valeurs, attendu in [([],[]),([18,19,22,28,29],[22]),
([20,25],[20,25]),([18,19],[])]:
mesures_test=[{'temperature': t} for t in valeurs]
alias=mesures_test
purger_mesures_extremes(mesures_test)
assert alias is mesures_test
assert [m['temperature'] for m in alias] == attenduPourquoi le parcours inverse est-il sûr ? À l’indice i, les cases à droite ont déjà été traitées. Supprimer i décale ces cases déjà traitées, mais ne change pas les indices strictement inférieurs à i. L’itération suivante peut donc examiner i−1 sans perdre de mesure. À l’inverse, dans un parcours croissant, l’élément i+1 devient i après la suppression ; avancer ensuite à i+1 le saute. Cette explication reste vraie pour deux, trois ou dix températures extrêmes consécutives, au-delà du seul exemple testé.
Suivre une purge correcte ou défaillanteUn atelier pour expérimenter
Choisissez une série et une stratégie. Chaque ligne montre la température examinée et la liste restante ; comparez les valeurs qui sont sautées.
Lire le résultat de l’expérience initiale
Valeurs conservées : 22.
Un parcours à rebours ne saute aucune case encore à examiner.
| Indice examiné | Température | Après traitement |
|---|---|---|
| 4 | 29 | 18, 19, 22, 28 |
| 3 | 28 | 18, 19, 22 |
| 2 | 22 | 18, 19, 22 |
| 1 | 19 | 18, 22 |
| 0 | 18 | 22 |
Changer une liste pendant son parcours demande une stratégie qui préserve les indices à visiter.
Du sujet à la méthode
Votre prochaine séance de révision
- Vérifier si une fonction doit renvoyer une nouvelle liste ou modifier la liste existante.
- Les températures exactement 20 et 25 sont des tests indispensables.
Retrouver ces notions dans d’autres sujets
Toutes les annales de NSI · Le guide pour préparer le bac NSI 2027
Énoncé : sujet 26_BCG_NSI_4 (PDF). Corrigé et explications pédagogiques proposés par Sofien.
