TP Remise en jambe - SD

Bases de Python et d’algorithmique
Author

Ludovic DENEUVILLE

Avant de commencer

Vous allez travailler sur le logiciel Visual Studio Code disponible sur les datalab :

Dans votre navigateur, vous arrivez sur VSCode.

Vous pouvez si vous le souhaitez choisir un thème (dark, light…).

En cas de besoin, VSCode est également installé sur vos VM ENSAI.

L’interface VSCode

Visual Studio Code (VS Code) est un éditeur de code moderne, gratuit et léger, qui permet d’écrire, exécuter et déboguer des programmes. Avec VSCode Server, on peut l’utiliser dans un navigateur web tout en gardant la puissance d’un serveur distant.

Son interface est composée de plusieurs parties principales :

  • Barre latérale gauche : permet d’accéder aux fichiers du projet, à la recherche, au contrôle de version, au débogage et aux extensions.
  • Explorateur de fichiers : affiche l’arborescence des dossiers et fichiers du projet.
  • Éditeur central : zone principale où l’on écrit et modifie le code.
  • Barre de statut (en bas) : donne des informations (erreurs, langage utilisé…).
  • Terminal intégré : en bas, permet de lancer des commandes (comme exécuter un script Python).

En haut de la barre latérale gauche, vous pouvez cliquer sur les 3 petits traits horizontaux pour accéder aux différents menus : File, Edit, Run, Terminal…

De nombreuses extensions sont disponibles pour VSCode. Par exemple, nous allons utiliser Ruff pour mettre en forme votre code.

    • Dans la barre latérale gauche > Extensions

Cloner un dépôt

Vous n’allez pas coder à partir d’une feuille blanche.

Votre base de départ sera ce dépôt de code https://github.com/ludo2ne/ENSAI-1A-SD-TP, dont vous allez créer un clone.

    • 3 petits traits horizontaux > Terminal > New
    • ou CTRL + ù
    • File > Open Folder : /home/onyxia/work/ENSAI-1A-SD-TP
    • dans le terminal : code-server ENSAI-1A-SD-TP
    • Modifiez l’url : https://...user.lab.sspcloud.fr/?folder=/home/onyxia/work/ENSAI-1A-SD-TP

Ce dépôt contient :

  • src/ : dossiers contenant les codes sources du TP (fichiers Python…)
  • README.md : description générale du projet, instructions pour démarrer
  • LICENSE : spécifie ce qu’on peut faire légalement avec le code : le réutiliser, le modifier, le distribuer
  • .gitignore : indique à Git quels fichiers ou dossiers ne doivent pas être versionnés
  • .vscode/settings.json : fichier de configuration pour VS Code
    • exemple : editor.formatOnSave: true

1 Python

Passons maintenant au code Python.

NotePourquoi apprendre Python ?
  • Langage polyvalent et populaire
  • Facilité d’apprentissage et de lecture, syntaxe claire et concise
  • Large communauté et nombreuses ressources
  • Nombreux packages (pandas, polars, numpy, matplotlib…)

Python est un langage interprété : le code est lu et exécuté directement ligne par ligne par un interpréteur.

1.1 Typage dynamique

Nul besoin d’indiquer le type des variables. Il est déterminé automatiquement au moment de l’exécution.

De plus une même variable peut changer de type sans quel ’on ait besoin de le préciser.

a = 1
print(type(a))

a = "youpi"
print(type(a))

1.2 Règles de base et bonnes pratiques

  • L’indentation (4 espaces) est obligatoire pour structurer le code
  • Les noms sont sensibles à la casse : Variable ≠ variable
  • Utilisez des noms de variables clairs et en minuscule_avec_underscores : ma_variable
  • Les lignes commentées commencent par #

2 Listes et boucles

Une liste en Python est une collection ordonnée et modifiable d’éléments, pouvant contenir des éléments de différents types.

# Création d'une liste
liste = ["Alice", "Benoit", "Camille", "Diane"]

liste.pop()           # Supprimer le dernier élément
liste.append(5.2)     # Ajouter un élément à la fin

nb_elements = len(liste)

if nb_elements == 0:
    print("La liste est vide")
elif not nb_elements > 0:
    print("Il y a un petit souci avec la fonction len")
else:
    print(f"Il y a {nb_elements} éléments dans la liste")

# Parcours par valeurs
for v in liste:
    print(v)

# Parcours par index
for i in range(len(liste)):
    print(liste[i])

# Parcours par index et valeurs
for i, v in enumerate(liste):
    print(f"index {i} : valeur {v}")

# Parcours par index avec une boucle While
index = 0
while index < len(liste):
    print(liste[index])
    index += 1
TipLa fonction range()

range(start, stop, step) sert à générer une suite de nombres entiers.

  • start : début (par défaut 0)
  • stop : fin (exclu, on s’arrête juste avant)
  • step : le pas (par défaut 1)
print(f"range(10)       : {list(range(10))}")
print(f"range(2, 10)    : {list(range(2, 10))}")
print(f"range(5, 10, 2) : {list(range(5, 10, 2))}")

2.1 Exercice

Pour générer un nombre aléatoire entre 1 et 9, utilisez le package random.

import random

random.randint(1, 9)

Tentons maintenant de copier la liste.

    • Vous trouvez ça normal ?

Lorsque vous fâites liste1 = liste2, vous ne créez pas une copie de la liste originale.

Vous avez simplement deux variables qui pointent vers le même espace mémoire.

Pour créer une copie, plusieurs possibilités :

liste1 = [1, 2, 3, 4]
liste2 = list(liste1)
liste3 = liste1.copy()

Une chaine de caractère peut être traitée comme une liste immuable de caractères.

3 Dictionnaire et autres conteneurs

Un dictionnaire est une structure de données qui associe des paires clé–valeur.

Il permet un accès rapide aux valeurs en utilisant leur clé.

ingredients = {"Fraise": 5, "Beurre": "100g", "Moutarde": "5g"}

ingredients["Sel"] = True    # Ajouter un élément
ingredients["Fraise"] = 10   # Modifier un élément
ingredients.pop("Moutarde")  # Supprimer

for k, v in ingredients.items():
    print(f"La clé {k} a pour valeur {v}")

Autres Collections utiles :

  • Set : collection non ordonnée de valeurs uniques

    premiers = {2, 3, 5, 7, 11, 13}
  • Tuple : collection ordonnée de valeurs immuables

    coord = (-1, 5, 4)

3.1 Exercice

dico.py
recette = {
    "nom": "Tartine Fraise-Moutarde",
    "instructions": [
        "Laver et couper les fraises.",
        "Étaler le beurre sur une tartine.",
        "Ajouter les fraises.",
    ],
    "ingredients": {"Fraise": 5, "Beurre": "100g"},
}

4 Fonctions

Vous devez écrire cette fonction : \(f(x) = \frac{5}{x}\) en Python

Définissons, puis utilisons cette fonction :

def diviser_cinq_par(nombre):
    return 5 / nombre

print(diviser_cinq_par(3))

Ok ça fonctionne dans le cas général.

Mais que se passe-t-il si nombre=0 ? Il faut gérer ce cas, par exemple :

def diviser_cinq_par(nombre):
    if nombre != 0:
        return 5 / nombre
    else:
        return None
        
print(diviser_cinq_par(0))

Ici, vous vous rendez compte que le else est facultatif.

def diviser_cinq_par(nombre):
    if nombre == 0:
        return None
    return 5 / nombre

Quand une fonction devient plus complexe, il est important de documenter i.e. :

  • expliquer ce que fait la fonction
  • indiquer les types des paramètres
  • indiquer le type de valeur retournée
def diviser_cinq_par(nombre: float) -> float | None:
    """Divise 5 par un nombre donné.

    Parameters
    ----------
    nombre : float
        Le nombre par lequel 5 sera divisé.

    Returns
    -------
    float | None
        Le résultat de la division de 5 par nombre.
        Retourne None si nombre est égal à 0.
    """
    if nombre == 0:
        return None
    return 5 / nombre

print(diviser_cinq_par("toto"))

Cependant, l’ajout des types de paramètres est purement indicatif.

Si l’on veut intégrer des restrictions, il faut vérifier les types dans le code :

def diviser_cinq_par(nombre: float) -> float | None:
    """Divise 5 par un nombre donné.
    """
    if not isinstance(nombre, (int, float)):
        return None
    if nombre == 0:
        return None
    return 5 / nombre

Enfin retourner None n’est pas très parlant, nous pouvons utiliser des Exceptions:

def diviser_cinq_par(nombre: float) -> float:
    """Divise 5 par un nombre donné.
    """
    if not isinstance(nombre, (int, float)):
        raise TypeError("L'argument doit être un nombre (int ou float).")
    if nombre == 0:
        raise ZeroDivisionError("Division par zéro interdite.")
    return 5 / nombre

# Exemple d'utilisation
try:
    resultat = diviser_cinq_par(0)
    print("Résultat :", resultat)
except ZeroDivisionError as e:
    print("Erreur :", e)
except TypeError as e:
    print("Erreur de type :", e)

4.1 Exercices

Fonction Pair

Factorielle

Écrivez trois fonctions qui calculent et retournent le factoriel d’un entier n :

Fibonacci

NoteRappel

La suite de Fibonacci \((F_{n})_{n\in \mathbb {N}}\) est définie par :

  • \(F_{0} = 0\)
  • \(F_{1} = 1\)
  • \(F_{n} = F_{n-1} + F_{n-2}\) pour \(n \geq 2\)

Le résultat attendu lorsque vous appelez votre fonction :

afficher_suite_fibonacci(15)  
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 

Brute force

import hashlib

pwd = "123456"
print(hashlib.md5(pwd.encode()).hexdigest())

Rugby

Au rugby, les façons de marquer des points sont :

  • Essai : 5 points
  • Essai transformé : 7 points
  • Pénalité ou Drop : 3 points

Pyramide

Exemple pour n=5
*********
 *******
  *****
   ***
    *

Maximum