Exercice 1 : QCM
Pour chaque question, une seule réponse est correcte.
1. Que renvoie la fonction suivante pour mystere(3, 5) ?
def mystere(a, b=10):
return a + b
- A. 8
- B. 13
- C. 15
- D. Une erreur
Correction
A. L’appel mystere(3, 5) passe a = 3 et b = 5 (le paramètre par défaut 10 est remplacé par la valeur fournie). Le résultat est $3 + 5 = 8$. B serait le résultat de mystere(3) (avec b = 10). C confond les paramètres. D est faux car l’appel est syntaxiquement correct.
2. Quel est le résultat de ce code ?
x = 10
def g():
x = 5
return x
print(g(), x)
- A.
5 5 - B.
5 10 - C.
10 10 - D.
10 5
Correction
B. Dans la fonction g, x = 5 crée une variable locale. La variable globale x reste à 10. Donc g() renvoie 5, mais x global vaut toujours 10. A serait le cas avec global x. C serait le cas si la fonction ne modifiait pas x localement.
3. Quelle est la complexité de la recherche d’une clé dans un dictionnaire Python ?
- A. $O(n)$
- B. $O(\log n)$
- C. $O(1)$ en moyenne
- D. $O(n^2)$
Correction
C. Les dictionnaires Python utilisent une table de hachage, ce qui permet un accès en $O(1)$ en moyenne. A est la complexité de la recherche dans une liste. B serait la recherche dichotomique.
4. Que produit le code suivant ?
d = {'a': 1, 'b': 2, 'c': 3}
d['b'] = 5
d['d'] = 4
print(len(d))
- A. 3
- B. 4
- C. 5
- D. Une erreur
Correction
B. Le dictionnaire commence avec trois clés. d['b'] = 5 modifie une clé existante (pas d’ajout). d['d'] = 4 ajoute une nouvelle clé. Total : quatre clés.
Exercice 2 : fonctions avec assertions et paramètres
a) Écrire une fonction moyenne(L) qui calcule la moyenne d’une liste de nombres. Ajouter une assertion vérifiant que la liste n’est pas vide et une docstring avec un exemple.
b) Écrire une fonction saluer(prenom, formule="Bonjour") qui renvoie une chaîne de la forme "Bonjour Marie". Que renvoient les appels suivants ?
saluer("Alice")
saluer("Bob", "Salut")
saluer(formule="Bonsoir", prenom="Clara")
c) Écrire une fonction clamp(x, mini=0, maxi=100) qui renvoie x si mini <= x <= maxi, sinon mini ou maxi selon le cas. Ajouter une assertion vérifiant que mini <= maxi.
d) Écrire une fonction presentation(*args) qui accepte un nombre variable de prénoms et renvoie "Bonjour Alice, Bob et Clara" (avec une virgule entre les prénoms sauf avant le dernier, précédé de « et »).
Correction
a)
def moyenne(L):
"""Calcule la moyenne d'une liste de nombres.
>>> moyenne([10, 12, 14])
12.0
"""
assert len(L) > 0, "La liste ne doit pas être vide"
return sum(L) / len(L)
b)
def saluer(prenom, formule="Bonjour"):
"""Renvoie une salutation personnalisée."""
return f"{formule} {prenom}"
saluer("Alice")→"Bonjour Alice"(formule par défaut) ;saluer("Bob", "Salut")→"Salut Bob"(formule explicite) ;saluer(formule="Bonsoir", prenom="Clara")→"Bonsoir Clara"(mots-clé, ordre libre).
c)
def clamp(x, mini=0, maxi=100):
"""Renvoie x borné entre mini et maxi."""
assert mini <= maxi, "mini doit être inférieur ou égal à maxi"
if x < mini:
return mini
if x > maxi:
return maxi
return x
Exemples : clamp(42) → 42, clamp(-5) → 0, clamp(150) → 100, clamp(7, 0, 10) → 7.
d)
def presentation(*args):
"""Renvoie une salutation pour un nombre variable de prénoms."""
if len(args) == 0:
return "Bonjour"
if len(args) == 1:
return f"Bonjour {args[0]}"
debut = ", ".join(args[:-1])
return f"Bonjour {debut} et {args[-1]}"
Vérification : presentation("Alice", "Bob", "Clara") → "Bonjour Alice, Bob et Clara".
Exercice 3 : dictionnaires – manipulation de base
On donne le dictionnaire suivant :
eleves = {
"Alice": {"age": 17, "moyenne": 14.5},
"Bob": {"age": 16, "moyenne": 12.0},
"Clara": {"age": 17, "moyenne": 16.5},
"David": {"age": 16, "moyenne": 9.5}
}
a) Écrire une fonction moyenne_classe(eleves) qui calcule la moyenne générale de la classe.
b) Écrire une fonction meilleur_eleve(eleves) qui renvoie le nom de l’élève ayant la meilleure moyenne.
c) Écrire une fonction eleves_par_age(eleves, age) qui renvoie la liste des noms des élèves ayant l’âge donné.
d) Ajouter l’élève « Emma », 17 ans, moyenne 15.0 au dictionnaire et recalculer la moyenne de la classe.
Correction
a)
def moyenne_classe(eleves):
"""Calcule la moyenne générale de la classe."""
total = sum(eleves[nom]["moyenne"] for nom in eleves)
return total / len(eleves)
Résultat : $(14.5 + 12.0 + 16.5 + 9.5) / 4 = 52.5 / 4 = 13.125$.
b)
def meilleur_eleve(eleves):
"""Renvoie le nom de l'élève avec la meilleure moyenne."""
meilleur = None
meilleure_moy = -1
for nom, infos in eleves.items():
if infos["moyenne"] > meilleure_moy:
meilleure_moy = infos["moyenne"]
meilleur = nom
return meilleur
Résultat : "Clara" (moyenne 16.5).
c)
def eleves_par_age(eleves, age):
"""Renvoie les noms des élèves ayant l'âge donné."""
return [nom for nom, infos in eleves.items()
if infos["age"] == age]
Exemple : eleves_par_age(eleves, 17) → ["Alice", "Clara"].
d)
eleves["Emma"] = {"age": 17, "moyenne": 15.0}
print(moyenne_classe(eleves))
Résultat : $(14.5 + 12.0 + 16.5 + 9.5 + 15.0) / 5 = 67.5 / 5 = 13.5$.
Exercice 4 : compréhensions de dictionnaires
a) Créer par compréhension un dictionnaire associant à chaque entier de 1 à 10 son carré.
b) À partir du dictionnaire {"a": 1, "b": 2, "c": 3, "d": 4}, créer par compréhension un nouveau dictionnaire ne contenant que les paires dont la valeur est paire.
c) Écrire une fonction inverser(d) qui renvoie un dictionnaire où les clés et valeurs sont échangées. Que se passe-t-il si deux clés ont la même valeur ?
Correction
a)
carres = {n: n**2 for n in range(1, 11)}
# {1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81, 10: 100}
b)
d = {"a": 1, "b": 2, "c": 3, "d": 4}
d_pairs = {k: v for k, v in d.items() if v % 2 == 0}
# {"b": 2, "d": 4}
c)
def inverser(d):
"""Renvoie un dictionnaire avec clés et valeurs échangées."""
return {v: k for k, v in d.items()}
Si deux clés ont la même valeur, seule la dernière paire sera conservée (les clés d’un dictionnaire sont uniques). Par exemple, inverser({"a": 1, "b": 1}) donne {1: "b"} (la paire 1: "a" est écrasée).
Exercice 5 : comptage et fréquences
a) Écrire une fonction compter_lettres(texte) qui renvoie un dictionnaire associant à chaque lettre (en minuscules) son nombre d’occurrences dans le texte.
b) Écrire une fonction lettre_frequente(texte) qui renvoie la lettre la plus fréquente.
c) Écrire une fonction compter_mots(phrase) qui renvoie un dictionnaire associant à chaque mot son nombre d’occurrences.
Correction
a)
def compter_lettres(texte):
"""Renvoie un dictionnaire des fréquences de chaque lettre."""
compteur = {}
for car in texte.lower():
if car.isalpha():
compteur[car] = compteur.get(car, 0) + 1
return compteur
Exemple : compter_lettres("Bonjour") → {'b': 1, 'o': 2, 'n': 1, 'j': 1, 'u': 1, 'r': 1}.
b)
def lettre_frequente(texte):
"""Renvoie la lettre la plus fréquente dans le texte."""
compteur = compter_lettres(texte)
return max(compteur, key=compteur.get)
c)
def compter_mots(phrase):
"""Renvoie un dictionnaire des fréquences de chaque mot."""
compteur = {}
for mot in phrase.lower().split():
compteur[mot] = compteur.get(mot, 0) + 1
return compteur
Exemple : compter_mots("le chat et le chien") → {'le': 2, 'chat': 1, 'et': 1, 'chien': 1}.
Exercice 6 : fonctions et dictionnaires combinés
a) Écrire une fonction statistiques(L) qui prend une liste de nombres et renvoie un dictionnaire contenant les clés "min", "max", "moyenne" et "nb_elements" avec les valeurs correspondantes.
b) Écrire une fonction fusionner(d1, d2) qui prend deux dictionnaires et renvoie un nouveau dictionnaire contenant toutes les paires clé-valeur des deux. Si une clé existe dans les deux, la valeur de d2 est conservée. Ne pas modifier d1 ni d2.
c) Écrire une fonction appliquer_remise(produits, remise=0.1) qui prend un dictionnaire {nom: prix} et renvoie un nouveau dictionnaire avec les prix réduits du pourcentage indiqué. La fonction ne doit pas modifier le dictionnaire original.
Correction
a)
def statistiques(L):
"""Renvoie un dictionnaire de statistiques sur la liste L."""
assert len(L) > 0, "La liste ne doit pas être vide"
return {
"min": min(L),
"max": max(L),
"moyenne": sum(L) / len(L),
"nb_elements": len(L)
}
Exemple : statistiques([3, 7, 2, 9, 4]) → {"min": 2, "max": 9, "moyenne": 5.0, "nb_elements": 5}.
b)
def fusionner(d1, d2):
"""Fusionne deux dictionnaires (d2 a priorité)."""
resultat = {}
for cle, val in d1.items():
resultat[cle] = val
for cle, val in d2.items():
resultat[cle] = val
return resultat
Ou plus simplement : return {**d1, **d2}.
Exemple : fusionner({"a": 1, "b": 2}, {"b": 3, "c": 4}) → {"a": 1, "b": 3, "c": 4}.
c)
def appliquer_remise(produits, remise=0.1):
"""Renvoie un nouveau dictionnaire avec les prix réduits."""
assert 0 <= remise <= 1, "La remise doit être entre 0 et 1"
return {nom: round(prix * (1 - remise), 2)
for nom, prix in produits.items()}
Exemple : appliquer_remise({"Cahier": 2.50, "Stylo": 1.20}) → {"Cahier": 2.25, "Stylo": 1.08}.
Exercice 7 : synthèse – carnet de contacts
On souhaite créer un carnet de contacts sous forme de dictionnaire de dictionnaires.
a) Écrire une fonction ajouter_contact(carnet, nom, telephone, email="") qui ajoute un contact au carnet. Si le contact existe déjà, ses informations sont mises à jour.
b) Écrire une fonction rechercher(carnet, nom) qui renvoie les informations du contact ou un message indiquant qu’il n’existe pas (en utilisant .get()).
c) Écrire une fonction supprimer_contact(carnet, nom) qui supprime un contact s’il existe, et affiche un message sinon.
d) Écrire une fonction exporter(carnet) qui renvoie une liste de chaînes formatées "Nom : tel - email", triée par nom.
e) Tester toutes ces fonctions avec un carnet contenant au moins quatre contacts.
Correction
a)
def ajouter_contact(carnet, nom, telephone, email=""):
"""Ajoute ou met à jour un contact dans le carnet."""
carnet[nom] = {"telephone": telephone, "email": email}
b)
def rechercher(carnet, nom):
"""Recherche un contact par son nom."""
contact = carnet.get(nom)
if contact is None:
return f"Contact '{nom}' non trouvé"
return contact
c)
def supprimer_contact(carnet, nom):
"""Supprime un contact s'il existe."""
if nom in carnet:
del carnet[nom]
print(f"Contact '{nom}' supprimé")
else:
print(f"Contact '{nom}' non trouvé")
d)
def exporter(carnet):
"""Exporte le carnet sous forme de liste triée."""
lignes = []
for nom in sorted(carnet):
tel = carnet[nom]["telephone"]
email = carnet[nom]["email"]
lignes.append(f"{nom} : {tel} - {email}")
return lignes
e) Test :
carnet = {}
ajouter_contact(carnet, "Dupont", "0612345678", "dupont@mail.fr")
ajouter_contact(carnet, "Martin", "0698765432", "martin@mail.fr")
ajouter_contact(carnet, "Leroy", "0611223344")
ajouter_contact(carnet, "Petit", "0655667788", "petit@mail.fr")
print(rechercher(carnet, "Martin"))
# {'telephone': '0698765432', 'email': 'martin@mail.fr'}
print(rechercher(carnet, "Durand"))
# Contact 'Durand' non trouvé
supprimer_contact(carnet, "Leroy")
# Contact 'Leroy' supprimé
for ligne in exporter(carnet):
print(ligne)
# Dupont : 0612345678 - dupont@mail.fr
# Martin : 0698765432 - martin@mail.fr
# Petit : 0655667788 - petit@mail.fr