Numérique et Sciences Informatiques1ère

Intégration des entrées/sorties dans les projets
Exercices corrigés

Maîtrisez l'intégration des entrées/sorties dans les projets : interfaces, validation, fichiers, API, interactions grâce à ces 5 exercices détaillés.

Concepts & Exercices
Projet = Entrées × Traitement × Sorties × Interaction
Formule de l'intégration des E/S dans les projets
🎯
Définition : L'intégration des entrées/sorties dans un projet consiste à gérer les interactions avec l'utilisateur et les flux de données.
📏
Objectifs : Créer des interfaces conviviales, valider les données, gérer les erreurs, optimiser les performances.
📐
Types : Interfaces console, graphiques, fichiers, bases de données, API web.
📝
Applications : Applications desktop, sites web, systèmes embarqués, jeux, outils de gestion.
💡
Conseil : Anticipez les erreurs de saisie utilisateur
🔍
Attention : Validez toujours les données entrantes
Astuce : Utilisez des widgets adaptés au type de données
📋
Méthode : Testez l'interface avec des données réalistes
Vérification : Vérifiez la sécurité des entrées/sorties
Cycle de développement d'interfaces

Analyse → Conception → Développement → Tests → Déploiement → Maintenance

Exercice 1
Concevoir une interface de gestion de contacts avec validation des données.
Exercice 2
Créer un programme de lecture et validation de fichiers CSV.
Exercice 3
Intégrer des opérations de base de données dans une application.
Exercice 4
Consommer une API externe et afficher les données dans une interface.
Exercice 5
Développer un jeu simple avec gestion des entrées utilisateur.
Corrigé : Exercices 1 à 3
1 Interface de gestion de contacts
Définition d'une interface de gestion :

Interface de gestion : Système permettant à l'utilisateur d'entrer, modifier, supprimer et afficher des données de manière organisée.

Méthodologie de développement :
  1. Analyser les besoins de l'utilisateur
  2. Concevoir l'interface utilisateur
  3. Implémenter la logique de gestion
  4. Valider les données entrantes
  5. Tester l'interface
Composants d'une interface de gestion
  • Champs de saisie
  • Boutons d'action
  • Zone d'affichage
  • Système de validation
  • Messages d'erreur
Étape 1 : Structure de l'interface
import tkinter as tk
from tkinter import messagebox

class GestionContacts:
    def __init__(self):
        self.fenetre = tk.Tk()
        self.fenetre.title("Gestion des contacts")
        self.contacts = []
        
        # Création des widgets
        self.creer_widgets()
    
    def creer_widgets(self):
        # Cadre principal
        cadre_principal = tk.Frame(self.fenetre, padx=20, pady=20)
        cadre_principal.pack(fill=tk.BOTH, expand=True)
Étape 2 : Champs de saisie
        # Champs pour nom
        tk.Label(cadre_principal, text="Nom :").grid(row=0, column=0, sticky=tk.W)
        self.champ_nom = tk.Entry(cadre_principal, width=30)
        self.champ_nom.grid(row=0, column=1, padx=10, pady=5)
        
        # Champs pour email
        tk.Label(cadre_principal, text="Email :").grid(row=1, column=0, sticky=tk.W)
        self.champ_email = tk.Entry(cadre_principal, width=30)
        self.champ_email.grid(row=1, column=1, padx=10, pady=5)
Étape 3 : Boutons d'action
        # Boutons
        cadre_boutons = tk.Frame(cadre_principal)
        cadre_boutons.grid(row=2, column=0, columnspan=2, pady=10)
        
        tk.Button(cadre_boutons, text="Ajouter", command=self.ajouter_contact).pack(side=tk.LEFT, padx=5)
        tk.Button(cadre_boutons, text="Afficher", command=self.afficher_contacts).pack(side=tk.LEFT, padx=5)
        tk.Button(cadre_boutons, text="Effacer", command=self.effacer_champs).pack(side=tk.LEFT, padx=5)
Interface complète de gestion de contacts
Réponse finale :
import tkinter as tk
from tkinter import messagebox
import re

class GestionContacts:
    def __init__(self):
        self.fenetre = tk.Tk()
        self.fenetre.title("Gestion des contacts")
        self.fenetre.geometry("500x400")
        self.contacts = []
        
        self.creer_widgets()
    
    def creer_widgets(self):
        cadre_principal = tk.Frame(self.fenetre, padx=20, pady=20)
        cadre_principal.pack(fill=tk.BOTH, expand=True)
        
        # Titre
        titre = tk.Label(cadre_principal, text="Gestion des contacts", font=("Arial", 16, "bold"))
        titre.grid(row=0, column=0, columnspan=2, pady=10)
        
        # Champs
        tk.Label(cadre_principal, text="Nom :").grid(row=1, column=0, sticky=tk.W)
        self.champ_nom = tk.Entry(cadre_principal, width=30)
        self.champ_nom.grid(row=1, column=1, padx=10, pady=5)
        
        tk.Label(cadre_principal, text="Email :").grid(row=2, column=0, sticky=tk.W)
        self.champ_email = tk.Entry(cadre_principal, width=30)
        self.champ_email.grid(row=2, column=1, padx=10, pady=5)
        
        # Boutons
        cadre_boutons = tk.Frame(cadre_principal)
        cadre_boutons.grid(row=3, column=0, columnspan=2, pady=10)
        
        tk.Button(cadre_boutons, text="Ajouter", command=self.ajouter_contact).pack(side=tk.LEFT, padx=5)
        tk.Button(cadre_boutons, text="Afficher", command=self.afficher_contacts).pack(side=tk.LEFT, padx=5)
        tk.Button(cadre_boutons, text="Effacer", command=self.effacer_champs).pack(side=tk.LEFT, padx=5)
        
        # Zone d'affichage
        tk.Label(cadre_principal, text="Contacts :").grid(row=4, column=0, sticky=tk.W, pady=(10,0))
        self.zone_affichage = tk.Text(cadre_principal, height=10, width=50)
        self.zone_affichage.grid(row=5, column=0, columnspan=2, pady=5)
    
    def valider_email(self, email):
        pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
        return re.match(pattern, email) is not None
    
    def ajouter_contact(self):
        nom = self.champ_nom.get().strip()
        email = self.champ_email.get().strip()
        
        if not nom:
            messagebox.showerror("Erreur", "Le nom est obligatoire")
            return
        
        if not email:
            messagebox.showerror("Erreur", "L'email est obligatoire")
            return
        
        if not self.valider_email(email):
            messagebox.showerror("Erreur", "Email invalide")
            return
        
        self.contacts.append({"nom": nom, "email": email})
        messagebox.showinfo("Succès", f"Contact {nom} ajouté")
        self.effacer_champs()
    
    def afficher_contacts(self):
        self.zone_affichage.delete(1.0, tk.END)
        for i, contact in enumerate(self.contacts):
            self.zone_affichage.insert(tk.END, f"{i+1}. {contact['nom']} - {contact['email']}\n")
    
    def effacer_champs(self):
        self.champ_nom.delete(0, tk.END)
        self.champ_email.delete(0, tk.END)
    
    def run(self):
        self.fenetre.mainloop()

# Exécution de l'application
app = GestionContacts()
app.run()
Lois et principes :

Validation préalable : Vérifier les données avant traitement

Interface intuitive : Organiser les éléments de manière logique

Messages clairs : Informer l'utilisateur des actions effectuées

2 Lecture et validation de fichiers CSV
Définition des fichiers CSV :

Fichiers CSV : Fichiers texte contenant des données tabulaires séparées par des virgules.

Étapes de lecture de CSV
  • Ouverture du fichier
  • Lecture des lignes
  • Validation des données
  • Transformation des types
  • Stockage dans une structure
Étape 1 : Importation du module
import csv
import os
Étape 2 : Vérification de l'existence
def lire_csv_valide(nom_fichier):
    if not os.path.exists(nom_fichier):
        print(f"Erreur : Fichier {nom_fichier} non trouvé")
        return None
Étape 3 : Lecture et validation
    with open(nom_fichier, 'r', encoding='utf-8') as f:
        lecteur = csv.DictReader(f)
        donnees = []
        
        for ligne in lecteur:
            # Validation des champs
            if valider_ligne(ligne):
                donnees.append(ligne)
            else:
                print(f"Ligne invalide ignorée : {ligne}")
        
        return donnees
Gestion complète de la lecture et validation de CSV
Réponse finale :
import csv
import os

def valider_ligne(ligne):
    """Valide une ligne de données CSV"""
    # Vérifier que les champs obligatoires sont présents
    champs_obligatoires = ['nom', 'email', 'age']
    for champ in champs_obligatoires:
        if not ligne.get(champ, '').strip():
            return False
    
    # Vérifier le format de l'email
    import re
    email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    if not re.match(email_pattern, ligne['email']):
        return False
    
    # Vérifier que l'âge est un nombre valide
    try:
        age = int(ligne['age'])
        if age < 0 or age > 150:
            return False
    except ValueError:
        return False
    
    return True

def lire_et_valider_csv(nom_fichier):
    """Lit et valide un fichier CSV"""
    if not os.path.exists(nom_fichier):
        print(f"Erreur : Fichier {nom_fichier} non trouvé")
        return []
    
    try:
        with open(nom_fichier, 'r', encoding='utf-8') as f:
            lecteur = csv.DictReader(f)
            donnees_valides = []
            erreurs = []
            
            for i, ligne in enumerate(lecteur, start=1):
                if valider_ligne(ligne):
                    # Convertir l'âge en entier
                    ligne['age'] = int(ligne['age'])
                    donnees_valides.append(ligne)
                else:
                    erreurs.append(f"Ligne {i} invalide : {ligne}")
            
            # Afficher les erreurs
            if erreurs:
                print("Erreurs détectées :")
                for erreur in erreurs:
                    print(erreur)
            
            return donnees_valides
            
    except Exception as e:
        print(f"Erreur lors de la lecture : {e}")
        return []

# Exemple d'utilisation
donnees = lire_et_valider_csv("contacts.csv")
print(f"{len(donnees)} contacts valides lus")
Lois et principes :

Existence du fichier : Vérifier avant l'ouverture

Validation ligne par ligne : Traiter chaque ligne individuellement

Conversion des types : Convertir les données après validation

3 Intégration de base de données dans une application
Définition de l'intégration :

Intégration de base de données : Connexion d'une application à une base de données pour stocker et récupérer des données.

Étapes d'intégration
  • Connexion à la base
  • Création des tables
  • Insertion des données
  • Requêtes de lecture
  • Fermeture de la connexion
Étape 1 : Importation du module
import sqlite3
Étape 2 : Connexion et création
def initialiser_base():
    connexion = sqlite3.connect('donnees.db')
    curseur = connexion.cursor()
    
    # Création de la table
    curseur.execute('''
        CREATE TABLE IF NOT EXISTS contacts (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            nom TEXT NOT NULL,
            email TEXT UNIQUE NOT NULL,
            telephone TEXT
        )
    ''')
    
    connexion.commit()
    return connexion
Étape 3 : Insertion sécurisée
def ajouter_contact(connexion, nom, email, telephone=None):
    curseur = connexion.cursor()
    try:
        curseur.execute(
            "INSERT INTO contacts (nom, email, telephone) VALUES (?, ?, ?)",
            (nom, email, telephone)
        )
        connexion.commit()
        print("Contact ajouté avec succès")
    except sqlite3.IntegrityError:
        print("Erreur : Email déjà existant")
Connexion sécurisée à une base de données SQLite
Réponse finale :
import sqlite3

class BaseDeDonnees:
    def __init__(self, nom_fichier):
        self.connexion = sqlite3.connect(nom_fichier)
        self.creer_tables()
    
    def creer_tables(self):
        """Crée les tables nécessaires"""
        curseur = self.connexion.cursor()
        
        curseur.execute('''
            CREATE TABLE IF NOT EXISTS contacts (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                nom TEXT NOT NULL,
                email TEXT UNIQUE NOT NULL,
                telephone TEXT,
                date_creation TIMESTAMP DEFAULT CURRENT_TIMESTAMP
            )
        ''')
        
        self.connexion.commit()
    
    def ajouter_contact(self, nom, email, telephone=None):
        """Ajoute un contact à la base"""
        curseur = self.connexion.cursor()
        try:
            curseur.execute(
                "INSERT INTO contacts (nom, email, telephone) VALUES (?, ?, ?)",
                (nom, email, telephone)
            )
            self.connexion.commit()
            print(f"Contact {nom} ajouté avec succès")
        except sqlite3.IntegrityError:
            print(f"Erreur : Contact avec email {email} déjà existant")
    
    def recuperer_contacts(self):
        """Récupère tous les contacts"""
        curseur = self.connexion.cursor()
        curseur.execute("SELECT * FROM contacts ORDER BY nom")
        return curseur.fetchall()
    
    def rechercher_par_email(self, email):
        """Recherche un contact par email"""
        curseur = self.connexion.cursor()
        curseur.execute("SELECT * FROM contacts WHERE email = ?", (email,))
        return curseur.fetchone()
    
    def fermer_connexion(self):
        """Ferme la connexion à la base"""
        self.connexion.close()

# Exemple d'utilisation
base = BaseDeDonnees('contacts.db')
base.ajouter_contact("Alice Martin", "alice@email.com", "0123456789")
base.ajouter_contact("Bob Dupont", "bob@email.com")

contacts = base.recuperer_contacts()
for contact in contacts:
    print(contact)

base.fermer_connexion()
Lois et principes :

Sécurité des requêtes : Utiliser des paramètres pour éviter l'injection SQL

Connexion sécurisée : Toujours fermer la connexion après utilisation

Validation des données : Vérifier les données avant insertion

Corrigé : Exercices 4 à 5
4 Consommation d'API externe
Définition d'une API :

API (Application Programming Interface) : Interface permettant à des programmes de communiquer entre eux.

Composants d'une requête API
  • URL de l'endpoint
  • Méthode HTTP (GET, POST, etc.)
  • Headers (authentification)
  • Paramètres de requête
  • Gestion des réponses
Étape 1 : Importation des modules
import requests
import json
Étape 2 : Requête de base
def recuperer_donnees_api(url):
    try:
        reponse = requests.get(url)
        if reponse.status_code == 200:
            return reponse.json()
        else:
            print(f"Erreur : Code {reponse.status_code}")
            return None
    except requests.RequestException as e:
        print(f"Erreur de requête : {e}")
        return None
Étape 3 : Traitement des données
def afficher_donnees(donnees):
    if donnees:
        for item in donnees:
            print(f"ID: {item.get('id')}, Nom: {item.get('name')}")
Intégration d'une API avec gestion des erreurs
Réponse finale :
import requests
import json

class ConsommateurAPI:
    def __init__(self, base_url):
        self.base_url = base_url
        self.headers = {'Content-Type': 'application/json'}
    
    def envoyer_requete(self, endpoint, params=None):
        """Envoie une requête GET à l'API"""
        url_complet = f"{self.base_url}/{endpoint}"
        
        try:
            reponse = requests.get(url_complet, params=params, headers=self.headers)
            
            if reponse.status_code == 200:
                return reponse.json()
            elif reponse.status_code == 404:
                print("Erreur 404 : Ressource non trouvée")
                return None
            elif reponse.status_code == 401:
                print("Erreur 401 : Non autorisé")
                return None
            else:
                print(f"Erreur {reponse.status_code} : {reponse.text}")
                return None
                
        except requests.ConnectionError:
            print("Erreur de connexion")
            return None
        except requests.Timeout:
            print("Délai de connexion dépassé")
            return None
        except Exception as e:
            print(f"Erreur inattendue : {e}")
            return None
    
    def recuperer_utilisateur(self, user_id):
        """Récupère un utilisateur par son ID"""
        return self.envoyer_requete(f"users/{user_id}")
    
    def recuperer_liste_utilisateurs(self, page=1):
        """Récupère une liste d'utilisateurs"""
        params = {'page': page}
        return self.envoyer_requete("users", params)
    
    def afficher_utilisateur(self, utilisateur):
        """Affiche les informations d'un utilisateur"""
        if utilisateur:
            print(f"Nom: {utilisateur.get('name', 'N/A')}")
            print(f"Email: {utilisateur.get('email', 'N/A')}")
            print(f"Site web: {utilisateur.get('website', 'N/A')}")
        else:
            print("Aucun utilisateur à afficher")

# Exemple d'utilisation avec une API publique
api = ConsommateurAPI("https://jsonplaceholder.typicode.com")
utilisateur = api.recuperer_utilisateur(1)
api.afficher_utilisateur(utilisateur)
Lois et principes :

Codes de statut : Vérifier le code de réponse HTTP

Gestion des erreurs : Capturer les exceptions de réseau

Sécurité : Utiliser HTTPS et authentification si nécessaire

5 Jeu simple avec gestion des entrées
Définition d'un jeu interactif :

Jeu interactif : Programme qui réagit aux actions de l'utilisateur en temps réel.

Composants d'un jeu simple
  • États du jeu
  • Gestion des entrées
  • Logique du jeu
  • Affichage
  • Boucle principale
Étape 1 : Structure de base
class JeuSimple:
    def __init__(self):
        self.etat = "menu"  # menu, jeu, pause, fin
        self.score = 0
        self.vie = 3
    
    def boucle_principale(self):
        while self.etat != "quitte":
            self.mettre_a_jour()
            self.afficher()
            self.gerer_entrees()
Étape 2 : Gestion des entrées
def gerer_entrees(self):
    # Dans une vraie application, capturer les événements clavier/souris
    commande = input("Entrez une commande (haut/bas/gauche/droite/quitter): ")
    
    if commande.lower() == "quitter":
        self.etat = "quitte"
    elif commande.lower() in ["haut", "bas", "gauche", "droite"]:
        self.deplacer_joueur(commande.lower())
Étape 3 : Logique du jeu
def deplacer_joueur(self, direction):
    # Mettre à jour la position du joueur
    if direction == "haut":
        self.joueur_y -= 1
    elif direction == "bas":
        self.joueur_y += 1
    # ... autres directions
Jeu avec gestion complète des entrées utilisateur
Réponse finale :
class JeuDevinette:
    def __init__(self):
        self.nombre_secret = self.generer_nombre_secret()
        self.tentatives = 0
        self.max_tentatives = 5
        self.termine = False
    
    def generer_nombre_secret(self):
        import random
        return random.randint(1, 100)
    
    def valider_entree(self, entree):
        """Valide que l'entrée est un nombre entre 1 et 100"""
        try:
            nombre = int(entree)
            return 1 <= nombre <= 100
        except ValueError:
            return False
    
    def gerer_entree_utilisateur(self):
        """Demande et valide l'entrée de l'utilisateur"""
        while True:
            entree = input(f"Tentative {self.tentatives + 1}/{self.max_tentatives} - Devinez un nombre entre 1 et 100 : ")
            
            if self.valider_entree(entree):
                return int(entree)
            else:
                print("Erreur : Veuillez entrer un nombre entre 1 et 100")
    
    def verifier_proposition(self, proposition):
        """Vérifie la proposition et met à jour l'état du jeu"""
        self.tentatives += 1
        
        if proposition == self.nombre_secret:
            print(f"Félicitations ! Vous avez trouvé le nombre {self.nombre_secret} en {self.tentatives} tentatives !")
            self.termine = True
        elif proposition < self.nombre_secret:
            print("Trop petit ! Essayez un nombre plus grand.")
        else:
            print("Trop grand ! Essayez un nombre plus petit.")
        
        if self.tentatives >= self.max_tentatives and not self.termine:
            print(f"Dommage ! Le nombre était {self.nombre_secret}")
            self.termine = True
    
    def jouer(self):
        """Boucle principale du jeu"""
        print("=== Jeu de Devinette ===")
        print("Devinez un nombre entre 1 et 100")
        print(f"Vous avez {self.max_tentatives} tentatives")
        
        while not self.termine:
            proposition = self.gerer_entree_utilisateur()
            self.verifier_proposition(proposition)
        
        print("Partie terminée !")

# Exemple d'utilisation
jeu = JeuDevinette()
jeu.jouer()
Lois et principes :

Validation continue : Vérifier chaque entrée utilisateur

Retours immédiats : Informer l'utilisateur des résultats

Limites de jeu : Définir des contraintes claires

Cours bien détaillé
E/S = Entrées × Validation × Sorties × Interaction × Sécurité
Formule des entrées/sorties dans les projets
🎯
Définition : Les entrées/sorties dans les projets consistent à gérer les interactions entre le programme et l'utilisateur ou les systèmes externes.
📏
Objectifs : Créer des interfaces conviviales, valider les données, gérer les erreurs, assurer la sécurité.
📐
Types : Interfaces console, graphiques, fichiers, bases de données, API, réseaux.
📝
Applications : Applications desktop, sites web, systèmes embarqués, jeux, outils de gestion.
💡
Conseil : Utilisez des bibliothèques spécialisées pour les interfaces
🔍
Attention : Protégez contre les injections SQL et XSS
Astuce : Validez les données côté client et serveur
📋
Méthode : Testez avec des données extrêmes
Vérification : Vérifiez la compatibilité multiplateforme
Étapes de développement des E/S :
  • Analyse des besoins : Identifier les types d'entrées/sorties
  • Conception : Planifier l'interface et les validations
  • Implémentation : Créer les composants et la logique
  • Validation : Tester avec diverses données
  • Sécurité : Protéger contre les attaques
  • Documentation : Expliquer l'utilisation
Concepts clés à retenir :
  • La validation des données est essentielle pour la sécurité
  • Les interfaces doivent être intuitives pour l'utilisateur
  • La gestion des erreurs améliore l'expérience utilisateur
  • Les API doivent être consommées de manière sécurisée
  • Les bases de données nécessitent des requêtes paramétrées
Processus de développement des E/S dans les projets

Spécifications → Conception → Développement → Validation → Sécurité → Déploiement

Utilisation en projets Entrées/Sorties et interaction