Adloun

Écrire fusion(d1, d2) renvoyant un nouveau dictionnaire contenant les…

Exercice de TD · niveau 2 · NSI (première), chapitre 5 — Les dictionnaires · Construire, lire, modifier

Énoncé

Écrire fusion(d1, d2) renvoyant un nouveau dictionnaire contenant les entrées des deux. Que décidez-vous pour une clé présente dans les deux ? Écrire cette décision dans la docstring, puis vérifier que d1 et d2 n'ont pas bougé.

Corrigé


def fusion(d1, d2):
    """Nouveau dictionnaire contenant les entrees de d1 et de d2.

    Precondition  : d1 et d2 sont des dictionnaires.
    Postcondition : les cles du resultat sont exactement celles de d1 et d2
                    reunies ; pour une cle presente dans les deux, c'est la
                    valeur de d2 qui est retenue -- d2 ECRASE d1.
    """
    resultat = {}
    for cle, valeur in d1.items():
        resultat[cle] = valeur
    for cle, valeur in d2.items():
        resultat[cle] = valeur
    return resultat

La décision est arbitraire ; l'écrire ne l'est pas. Rien, dans l'énoncé, n'impose que d2 l'emporte : on aurait pu garder d1, ou refuser la fusion par une précondition, ou renvoyer une liste des deux valeurs. Ce qui n'est pas facultatif, c'est de dire ce qu'on a choisi. Une fonction dont la docstring se tait sur les clés communes oblige chaque lecteur à relire le code — et à le relire encore le mois suivant.

Pourquoi d2 écrase sans qu'on l'écrive nulle part. Aucune ligne du corps ne teste la présence d'une clé : c'est la règle du chapitre — « la même syntaxe crée et modifie » — qui fait tout le travail. La seconde boucle écrase les entrées déjà posées par la première, simplement parce qu'elle passe après. Le comportement vient de l'ordre des deux boucles, et c'est bien pour cela qu'il faut le documenter : il est invisible à la lecture.

Vérification.


a = {"pain": 2, "lait": 1}
b = {"lait": 3, "oeufs": 6}
assert fusion(a, b) == {"pain": 2, "lait": 3, "oeufs": 6}
assert fusion(b, a) == {"lait": 1, "oeufs": 6, "pain": 2}
assert a == {"pain": 2, "lait": 1}          # a n'a pas bouge
assert fusion({}, {}) == {}

for _ in range(2000):
    d1 = {random.randint(0, 9): random.randint(0, 9)
          for _ in range(random.randint(0, 6))}
    d2 = {random.randint(0, 9): random.randint(0, 9)
          for _ in range(random.randint(0, 6))}
    f = fusion(d1, d2)
    assert set(f) == set(d1) | set(d2)
    assert len(f) <= len(d1) + len(d2)

Les deux premiers assert ne sont pas redondants : ils vérifient que fusion(a, b) et fusion(b, a) diffèrent. Le troisième garde l'essentiel — la fonction ne modifie pas ses arguments. Les tirages contrôlent que le résultat a bien les clés des deux réunies, et au plus autant d'entrées que la somme des deux : l'inégalité est stricte dès qu'une clé est commune.

Les autres exercices de ce chapitre Le cours du chapitre

Un blocage sur cet exercice ? Le tuteur d'Adloun guide par questions, sans donner la réponse.