Banque d’exercices

Cette page regroupe les exercices proposés au gré de la formation.

Certains des exercices sont des classiques revisités et d’autres sont librement inspirés d”ici et de

Exercice 1 : double

Énoncé

Section Introduction aux fonctions

Écrire la fonction double(x) qui renvoie le double de x.

Vérifier les résultats de cette fonction avec assert, par exemple:

assert double(21) == 42
assert double(0) == 0
assert double(-99) == -198
assert double(3150) == 6300

Voir ce qui se passe avec

assert double(5)==9

Solution

[5]:
def double(x):
    return 2*x
[6]:
assert double(21) == 42
assert double(0) == 0
assert double(-99) == -198
assert double(3150) == 6300
[7]:
assert double(5)==9
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
Cell In[7], line 1
----> 1 assert double(5)==9

AssertionError:

Exercice 2 : conversion de température

Énoncé

Section Introduction aux fonctions

Écrire la fonction to_celsius(temp) qui renvoie en °C la température temp donnée en °F.

La formule est donnée par $ Celsius = :nbsphinx-math:frac{5}{9}`(Fahrenheit - 32) $ <https://fr.wikipedia.org/wiki/Degr%C3%A9_Fahrenheit>`__.

Écrire la fonction inverse to_farenheit(temp).

Vérifier les résultats :

assert to_celsius(32) == 0
assert to_farenheit(100) == 212
assert to_celsius(-40) == -40
assert to_farenheit(-40) == -40
assert to_celsius(to_farenheit(15.)) == 15.

source de l’exercice

Solution

[15]:
def to_celsius(temp):
    return 5/9 * (temp-32)

def to_farenheit(temp):
    return temp * 9/5 +32
[16]:
assert to_celsius(32) == 0
assert to_farenheit(100) == 212
assert to_celsius(-40) == -40
assert to_farenheit(-40) == -40
assert to_celsius(to_farenheit(15.)) == 15.

Exercice 3 : conversion de secondes

Énoncé

Section Introduction aux fonctions

Écrire une fonction h_m_s(seconds) qui convertit un nombre total de secondes h_m_s(seconds) en heures, minutes et secondes sous la forme d’une chaine de caractères. Les nombres seront des entiers, et les secondes restantes seront arrondies à l’entier inférieur.

Vérifier les résultats :

assert h_m_s(0) == '0h 0m 0s'
assert h_m_s(60) == '0h 1m 0s'
assert h_m_s(3600) == '1h 0m 0s'
assert h_m_s(5700) == '1h 35m 0s'
assert h_m_s(18453) == '5h 7m 33s'
assert h_m_s(60.12586) == '0h 1m 0s'

Étape 2

Section Structure de contrôle

Mettre à jour la fonction pour qu’elle n’affiche les heures et minutes que si nécessaire.

assert h_m_s(0) == '00s'
assert h_m_s(60) == '01m 00s'
assert h_m_s(3600) == '1h 00m 00s'
assert h_m_s(5700) == '1h 35m 00s'
assert h_m_s(18453) == '5h 07m 33s'
assert h_m_s(60.12586) == '01m 00s'

Étape 3

Section Utilisation avancée des chaines de caractères

Mettre à jour la fonction afin qu’elle affiche les minutes et les secondes sur 2 caractères.

assert h_m_s(0) == '00s'
assert h_m_s(60) == '01m 00s'
assert h_m_s(3600) == '1h 00m 00s'
assert h_m_s(5700) == '01h 35m 00s'
assert h_m_s(18453) == '05h 07m 33s'
assert h_m_s(60.12586) == '01m 00s'

source de l’exercice

Solution (étape 1)

[34]:
def h_m_s(seconds):
    seconds = int(seconds)
    hours = seconds//3600
    seconds = seconds%3600
    minutes = seconds//60
    seconds = seconds%60
    result = str(hours) + 'h ' + str(minutes) + 'm ' + str(seconds) + 's'
    return result
[35]:
assert h_m_s(0) == '0h 0m 0s'
assert h_m_s(60) == '0h 1m 0s'
assert h_m_s(3600) == '1h 0m 0s'
assert h_m_s(5700) == '1h 35m 0s'
assert h_m_s(18453) == '5h 7m 33s'
assert h_m_s(60.12586) == '0h 1m 0s'

Solution (étape 2, avec if)

[36]:
def h_m_s(seconds):
    seconds = int(seconds)
    hours = seconds//3600
    seconds = seconds%3600
    minutes = seconds//60
    seconds = seconds%60
    if hours > 0:
        result = str(hours) + 'h ' + str(minutes) + 'm '
    elif minutes > 0:
        result = str(minutes) + 'm '
    else:
        result = ''
    result = result + str(seconds) + 's'
    return result
[37]:
assert h_m_s(0) == '0s'
assert h_m_s(60) == '1m 0s'
assert h_m_s(3600) == '1h 0m 0s'
assert h_m_s(5700) == '1h 35m 0s'
assert h_m_s(18453) == '5h 7m 33s'
assert h_m_s(60.12586) == '1m 0s'

Solution (étape 3, avec f-string)

[38]:
def h_m_s(seconds):
    seconds = int(seconds)
    hours = seconds//3600
    seconds = seconds%3600
    minutes = seconds//60
    seconds = seconds%60
    if hours > 0:
        hours = f'{hours}h '
    else:
        hours = ''
    if minutes > 0 or hours:
        minutes = f'{minutes:>02}m '
    else:
        minutes = ''
    seconds = f'{seconds:>02}s'
    return f'{hours}{minutes}{seconds}'
[39]:
assert h_m_s(0) == '00s'
assert h_m_s(60) == '01m 00s'
assert h_m_s(3600) == '1h 00m 00s'
assert h_m_s(5700) == '1h 35m 00s'
assert h_m_s(18453) == '5h 07m 33s'
assert h_m_s(60.12586) == '01m 00s'

Exercice 4 : liste de zéros

Énoncé

Section Les conteneurs de base

Créer une fonction make_zeros_list(nzeros) qui renvoie une liste avec nzeros 0 sous la forme de flottants.

La fonction s’assurera que nzeros est un entier positif mais traitera le cas nzeros=0.

Vérifier les résultats :

assert make_zeros_list(5) == [0., 0., 0., 0., 0.]
assert make_zeros_list(1) == [0.]
assert make_zeros_list(0) == []

Solution

[1]:
def make_zeros_list(nzeros):
    assert isinstance(nzeros, int)
    assert nzeros >= 0
    return [0.]*nzeros
[2]:
assert make_zeros_list(5) == [0., 0., 0., 0., 0.]
assert make_zeros_list(1) == [0.]
assert make_zeros_list(0) == []

Exercice 5 : compte occurences

Énoncé

Section Structure de contrôle

Ecrire une fonction compte_occurences(chaîne) qui compte le nombre d’occurrences de chaque caractère dans la chaîne de caractères chaîne. La fonction retournera un dict où les clés seront les caractères rencontrés et les valeurs, le nombre d’occurences de chaque caractère.

Vérifier les résultats :

assert compte_occurences('python') == {'h': 1,'n': 1, 'o': 1, 'p': 1, 't': 1, 'y': 1}
assert compte_occurences('cool') == {'c': 1, 'l': 1, 'o': 2}

Étape 2

Section Utilisation avancée des conteneurs

Mettre à jour la fonction en utilisant une/des méthode(s) des dictionnaires.

Vérifier les résultats (identiques aux précédents)

Bonus

Section Qu’est-ce qu’un module ?

La librairie standard ne proposerait-elle pas déjà quelque chose? Au hasard, module collections?

Vérifier les résultats (identiques aux précédents)

Solution (étape 1)

[2]:
def compte_occurences(chaîne):
    mon_dico = {}
    for char in chaîne:
        if char in mon_dico:
            mon_dico[char] += 1
        else:
            mon_dico[char] = 1
    return mon_dico
[3]:
assert compte_occurences('python') == {'h': 1,'n': 1, 'o': 1, 'p': 1, 't': 1, 'y': 1}
assert compte_occurences('cool') == {'c': 1, 'l': 1, 'o': 2}

Solution (étape 2, avec méthode)

[25]:
def compte_occurences(chaîne):
    mon_dico = {}
    for char in chaîne:
        mon_dico[char] = mon_dico.get(char, 0) + 1
    return mon_dico

def compte_occurences(chaîne):
    # Variante
    mon_dico = {}
    for char in chaîne:
        mon_dico.setdefault(char, 0)
        mon_dico[char] += 1
    return mon_dico
[26]:
assert compte_occurences('python') == {'h': 1,'n': 1, 'o': 1, 'p': 1, 't': 1, 'y': 1}
assert compte_occurences('cool') == {'c': 1, 'l': 1, 'o': 2}

Solution (bonus)

[68]:
from collections import Counter as compte_occurences
[69]:
assert compte_occurences('python') == {'h': 1,'n': 1, 'o': 1, 'p': 1, 't': 1, 'y': 1}
assert compte_occurences('cool') == {'c': 1, 'l': 1, 'o': 2}

Pourtant, ce que retourne la fonction n’est pas un dictionnaire?

[70]:
compte_occurences('python')
[70]:
Counter({'p': 1, 'y': 1, 't': 1, 'h': 1, 'o': 1, 'n': 1})

Mais, Python s’occupe de la conversion derrière le rideau lors du test de comparaison!

[71]:
dict(compte_occurences('python'))
[71]:
{'p': 1, 'y': 1, 't': 1, 'h': 1, 'o': 1, 'n': 1}

Exercice 6 : suite de Collatz

Énoncé

Section Structure de contrôle

Construire une fonction collatz(n) qui, partant d’un nombre entier n, construit la suite de Collatz qui est définie selon :

         | u(n)/2   si u(n) est pair
u(n+1) = |
         | 3u(n)+1  sinon

La fonction vérifiera que n est un entier positif et retournera une liste avec les valeurs de la suite.

NB: arrêter la boucle de construction dès lors que u(n) = 1 (conjecture de Collatz)

Vérifier les résultats :

assert collatz(1) == [1]
assert collatz(10) == [10, 5, 16, 8, 4, 2, 1]
assert collatz(11) == [11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]
assert collatz(12) == [12, 6, 3, 10, 5, 16, 8, 4, 2, 1]
assert len(collatz(256)) == 9
assert len(collatz(257)) == 123

source de l’exercice

Bonus

Section Les générateurs

Plutôt que de retourner une liste, on pourrait produire un générateur : gen_collatz(n).
L’intérêt est d’économiser de la mémoire, mais il peut être moins évident d’interroger la séquence : valeur maximum ? taille ?

Solution

[45]:
def collatz(n):
    assert isinstance(n, int)
    assert n > 0
    sequence = [n]
    while n != 1:
        is_even = n%2==0
        if is_even:
            n //= 2
        else:
            n = 3*n+1
        sequence.append(n)
    return sequence
[46]:
assert collatz(1) == [1]
assert collatz(10) == [10, 5, 16, 8, 4, 2, 1]
assert collatz(11) == [11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]
assert collatz(12) == [12, 6, 3, 10, 5, 16, 8, 4, 2, 1]
assert len(collatz(256)) == 9
assert len(collatz(257)) == 123

Solution (bonus)

[2]:
def gen_collatz(n):
    assert isinstance(n, int)
    assert n > 0
    yield n
    while n != 1:
        is_even = n%2==0
        if is_even:
            n //= 2
        else:
            n = 3*n+1
        yield n
[4]:
assert list(gen_collatz(1)) == [1]
assert list(gen_collatz(10)) == [10, 5, 16, 8, 4, 2, 1]
assert list(gen_collatz(11)) == [11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]
assert list(gen_collatz(12)) == [12, 6, 3, 10, 5, 16, 8, 4, 2, 1]
assert len(list(gen_collatz(256))) == 9
assert len(list(gen_collatz(257))) == 123
assert max(gen_collatz(10)) == 16
assert max(gen_collatz(11)) == 52
assert max(gen_collatz(12)) == 16

Exercice 7 : statistiques d’un échantillon

Énoncé

Section Lire et écrire des fichiers

Créer une fonction get_stats(fname) qui renvoie les minimum, maximum, moyenne et écart-type d’une liste de nombres lus dans un fichier de nom fname.

Le résultat se fera sous la forme d’un dictionnaire de clés 'min', 'max', 'mean', 'std'.

NB :

  • les fonctions min, max, mean, std peuvent être importées depuis le module numpy

  • on admettra que le fichier d’entrée n’a qu’une seule valeur par ligne, du type :

3548.279704
3589.7804263
3095.09156402
...

Vérifier les résultats :

assert get_stats('demo_stats.txt') # s'assure que la fonction ne retourne pas un dictionnaire vide
assert get_stats('demo_stats.txt')['min'] == 2561.50070722
assert get_stats('demo_stats.txt')['max'] == 3722.25284478
assert np.allclose(get_stats('demo_stats.txt')['mean'], 3150)
assert np.allclose(get_stats('demo_stats.txt')['std'], 314)

Solution

[54]:
import numpy as np

def get_stats(fname):
    values = []
    with open(fname) as rd:
        for line in rd:
            values.append(float(line.strip()))
    return dict(
        min=np.min(values),
        max=np.max(values),
        mean=np.mean(values),
        std=np.std(values)
    )
[66]:
assert get_stats('demo_stats.txt') # s'assure que la fonction ne retourne pas un dictionnaire vide
assert get_stats('demo_stats.txt')['min'] == 2561.50070722
assert get_stats('demo_stats.txt')['max'] == 3722.25284478
assert np.allclose(get_stats('demo_stats.txt')['mean'], 3150)
assert np.allclose(get_stats('demo_stats.txt')['std'], 314)

Bonus

Ne pas réinventer la roue, des librairies font très bien le travail!

[67]:
import pandas as pd
values = pd.read_csv('demo_stats.txt', names=['Sample'])
values.describe()
[67]:
Sample
count 50.000000
mean 3150.000000
std 317.187899
min 2561.500707
25% 2950.424439
50% 3160.149710
75% 3414.406663
max 3722.252845

Exercice 8 : filtrage de liste

Énoncé

Section Listes en intension

Créer une fonction keep_positive(values) qui recoit une liste de valeurs et renvoie une liste similaire mais avec seulement les valeurs positives.

Vérifier les résultats :

assert keep_positive([4, 5, 2, 9]) == [4, 5, 2, 9]
assert keep_positive([1, -2, 3, -4]) == [1, 3]
assert keep_positive([-1, -2]) == []

Solution

[8]:
keep_positive = lambda values: [v for v in values if v>=0]
[9]:
assert keep_positive([4, 5, 2, 9]) == [4, 5, 2, 9]
assert keep_positive([1, -2, 3, -4]) == [1, 3]
assert keep_positive([-1, -2]) == []

Exercice 9 : matrice de zéros

Enoncé

Section Noms et objets non immuables

Créer une fonction make_zeros_matrix(nrows, ncols) qui produit une liste de nrows listes, chacune remplie de ncols zéros.
Cette structure imbriquée est un prototype pour une représentation de matrice, on peut jouer à y affecter des valeurs dans des cellules via une double indexation.

Une idée pourrait être la suivante:

# It's a trap !
def make_zeros_matrix(nrows, ncols):
    return [[0] * ncols] * nrows

Mais il s’avère que la matrice produite a un problème… lequel ?

Vérifier les résultats :

assert make_zeros_matrix(1, 1) == [[0]]
assert make_zeros_matrix(4, 0) == [[], [], [], []]
assert make_zeros_matrix(0, 4) == []
assert make_zeros_matrix(3, 2) == [[0, 0],
                                   [0, 0],
                                   [0, 0]]
mat = make_zeros_matrix(2, 3)
assert mat == [[0, 0, 0],
               [0, 0, 0]]
mat[0][0] = 1
assert mat == [[1, 0, 0],
               [0, 0, 0]]

Solution

[20]:
def make_zeros_matrix(nrows, ncols):
    matrix = []
    for _ in range(nrows):
        matrix.append([0] * ncols)
    return matrix
[21]:
assert make_zeros_matrix(1, 1) == [[0]]
assert make_zeros_matrix(4, 0) == [[], [], [], []]
assert make_zeros_matrix(0, 4) == []
assert make_zeros_matrix(3, 2) == [[0, 0],
                                   [0, 0],
                                   [0, 0]]
mat = make_zeros_matrix(2, 3)
assert mat == [[0, 0, 0],
               [0, 0, 0]]
mat[0][0] = 1
assert mat == [[1, 0, 0],
               [0, 0, 0]]

Quel est le problème avec la suggestion de l’énoncé ?

La structure imbriquée construite contient en fait UNE SEULE LISTE POUR TOUTES LES LIGNES !!!

Modifier une ligne va modifier cette liste, et donc modifier toutes les lignes…

[2]:
def wrong_make_zeros_matrix(nrows, ncols):
    return [[0] * ncols] * nrows

wrong_mat = wrong_make_zeros_matrix(2, 3)
wrong_mat[0][0] = 1
assert wrong_mat == [[1, 0, 0],
                     [1, 0, 0]]  # <- cette ligne ne devrait pas être modifiée !

La preuve en images ci-dessous

lien

[1]:
from IPython.display import IFrame
IFrame("https://pythontutor.com/iframe-embed.html#code=def%20wrong_make_zeros_matrix%28nrows,%20ncols%29%3A%0A%20%20%20%20return%20%5B%5B0%5D%20*%20ncols%5D%20*%20nrows%0A%0Awrong_mat%20%3D%20wrong_make_zeros_matrix%282,%203%29%0Awrong_mat%5B0%5D%5B0%5D%20%3D%201&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false",
       width='100%', height=300)
[1]: