Développement itératif d'un programme calculatrice en Python

La création d'une calculatrice est un exercice classique pour mettre en pratique les concepts fondamentaux de la programmation, tels que les structures de contrôle et la logique. Ce projet a été réalisé en plusieurs étapes pour en enrichir progressivement les fonctionnalités.

Phase initiale : Opérations de base avec interaction utilisateur

La première version consistait en un script permettant d'effectuer des opérations simples (addition, soustraction, multiplication, division, logarithme) sur deux nombres. Le choix entre nombres réels et complexes était proposé à l'utilisateur. Une boucle permettait de répéter l'opération.


import math

def effectuer_addition(a, b):
    return a + b

def effectuer_soustraction(a, b):
    return a - b

def effectuer_multiplication(a, b):
    return a * b

def effectuer_division(a, b):
    if b == 0:
        print("Division par zéro impossible.")
        return None
    return a / b

def calculer_logarithme(base, argument):
    if base <= 0 or argument <= 0:
        print("Les valeurs doivent être positives pour le logarithme.")
        return None
    return math.log(argument, base)

mode_actif = True
while mode_actif:
    type_nombre = input("Calcul avec (1) nombres complexes ou (2) réels ?\n")
    if type_nombre == "1":
        premier = complex(input("Entrez le premier nombre : "))
        deuxieme = complex(input("Entrez le deuxième nombre : "))
    else:
        premier = float(input("Entrez le premier nombre : "))
        deuxieme = float(input("Entrez le deuxième nombre : "))

    operateur = input("Choisissez l'opérateur (+, -, *, /, log) : ")
    resultat = None

    if operateur == "+":
        resultat = effectuer_addition(premier, deuxieme)
    elif operateur == "-":
        resultat = effectuer_soustraction(premier, deuxieme)
    elif operateur == "*":
        resultat = effectuer_multiplication(premier, deuxieme)
    elif operateur == "/":
        resultat = effectuer_division(premier, deuxieme)
    elif operateur == "log":
        resultat = calculer_logarithme(premier, deuxieme)

    if resultat is not None:
        print(f"Résultat : {premier} {operateur} {deuxieme} = {resultat}")

    suite = input("Effectuer un autre calcul ? (O/N)\n")
    if suite.upper() != "O":
        mode_actif = False

Évolution : Saisei d'expressions multiples et chaînées

Pour améliorer l'ergonomie, la version suivante a permis de saisir une séquence de nombres et d'opérateurs jusqu'à rencontrer le signe '='. Le calcul s'effectuait alors séquentiellement, de gauche à droite.


import math
# ... (Les fonctions d'opération sont identiques à la version précédente)

calcul_en_cours = True
while calcul_en_cours:
    liste_nombres = []
    liste_operations = []
    type_mode = input("Mode (1) complexe, (2) réel ?\n")

    if type_mode == "1":
        while True:
            val = complex(input())
            op = input()
            liste_nombres.append(val)
            liste_operations.append(op)
            if op == "=":
                break
    else:
        while True:
            val = float(input())
            op = input()
            liste_nombres.append(val)
            liste_operations.append(op)
            if op == "=":
                break

    accumulateur = liste_nombres[0]
    compteur = 1
    while compteur < len(liste_operations):
        op_courante = liste_operations[compteur - 1]
        if op_courante == "=":
            break
        valeur_suivante = liste_nombres[compteur]

        if op_courante == "+":
            accumulateur = effectuer_addition(accumulateur, valeur_suivante)
        elif op_courante == "-":
            accumulateur = effectuer_soustraction(accumulateur, valeur_suivante)
        elif op_courante == "*":
            accumulateur = effectuer_multiplication(accumulateur, valeur_suivante)
        elif op_courante == "/":
            accumulateur = effectuer_division(accumulateur, valeur_suivante)
        elif op_courante == "log":
            accumulateur = calculer_logarithme(accumulateur, valeur_suivante)
        compteur += 1

    print(f"Résultat final : {accumulateur}")
    reprendre = input("Nouveau calcul ? (O/N)\n")
    calcul_en_cours = reprendre.upper() == "O"

Version finale : Gestion des priorités opératoires

L'étape cruciale a été d'implémenter la priorité des opérateurs (multiplication et division avant addition et soustraction). Cela a nécessité la conception d'un algorithme d'évaluation en deux passes.


import math
# ... (Les fonctions d'opération restent similaires)

def evaluer_expression(nombres, operateurs):
    """Évalue une expression en respectant les priorités."""
    # Première passe : traiter les opérations à haute priorité (*, /, log)
    index = 0
    while index < len(operateurs):
        op = operateurs[index]
        if op in ('*', '/', 'log'):
            val_gauche = nombres[index]
            val_droite = nombres[index + 1]
            resultat_intermediaire = None

            if op == '*':
                resultat_intermediaire = effectuer_multiplication(val_gauche, val_droite)
            elif op == '/':
                resultat_intermediaire = effectuer_division(val_gauche, val_droite)
            elif op == 'log':
                resultat_intermediaire = calculer_logarithme(val_gauche, val_droite)

            # Remplacer les deux opérandes et l'opérateur par le résultat
            nombres[index] = resultat_intermediaire
            del nombres[index + 1]
            del operateurs[index]
            # Ne pas incrémenter l'index car les listes ont été réduites
        else:
            index += 1

    # Deuxième passe : calculer les opérations restantes (+, -)
    resultat_final = nombres[0]
    for i in range(len(operateurs)):
        operande = nombres[i + 1]
        op = operateurs[i]
        if op == '+':
            resultat_final = effectuer_addition(resultat_final, operande)
        elif op == '-':
            resultat_final = effectuer_soustraction(resultat_final, operande)

    return resultat_final

session_active = True
while session_active:
    liste_val = []
    liste_op = []
    mode = input("Mode (1) complexe, (2) réel ?\n")

    try:
        if mode == "1":
            while True:
                nombre = complex(input())
                operation = input()
                liste_val.append(nombre)
                liste_op.append(operation)
                if operation == "=":
                    break
        else:
            while True:
                nombre = float(input())
                operation = input()
                liste_val.append(nombre)
                liste_op.append(operation)
                if operation == "=":
                    break

        # On passe des copies pour ne pas altérer les listes originales
        expression_val = liste_val.copy()
        expression_op = liste_op[:-1].copy() # On exclut le '=' final
        resultat = evaluer_expression(expression_val, expression_op)
        print(f"Résultat de l'expression : {resultat}")

    except (ValueError, ZeroDivisionError, TypeError) as e:
        print(f"Erreur dans le calcul ou la saisie : {e}")
    except IndexError:
        print("Expression mal formée.")

    continuation = input("Continuer ? (O/N)\n")
    if continuation.upper() != 'O':
        session_active = False

Un point d'apprentissage important a été le placement de l'initialisation de l'index à l'intérieur de la boucle principale pour chaque nouveau calcul, sinon les calculs itératifs produisaient des errreurs. De plus, l'utilisation de blocs try...except s'est avérée essentielle pour gérer proprement les erreurs de saisie (ValueError) et les erreurs de calcul (ZeroDivisionError).

Étiquettes: Python calculatrice gestion-exceptions structures-donnees boucles-conditions

Publié le 17 juillet à 06h32