Exercices Projets guidés Outil : calculatrice securisee
🎉

Bravo!

Débutant 🧠 Fondamentaux 10 XP 0 personnes ont réussi

Outil : calculatrice securisee

Les LLM sont nuls en maths. Demande a ChatGPT de calculer 17.3 * 28.7 et il y a de bonnes chances qu'il se trompe. C'est logique : un modele de langage predit le prochain token, il ne fait pas d'arithmetique. La solution, c'est de lui donner un outil calculatrice.

Mais attention : pas question d'utiliser eval() pour executer du code arbitraire. Si un utilisateur envoie eval("__import__('os').system('rm -rf /')"), c'est la catastrophe. Il faut une calculatrice qui ne peut faire que des maths.

La solution propre passe par le module ast (Abstract Syntax Tree) de Python. Tu peux parser une expression mathematique en arbre syntaxique et n'evaluer que les operations autorisees : addition, soustraction, multiplication, division, puissance, et les nombres.

Voici l'idee :

import ast
import operator

OPERATIONS = {
ast.Add: operator.add,
ast.Sub: operator.sub,
ast.Mult: operator.mul,
ast.Div: operator.truediv,
ast.Pow: operator.pow,
}

def evaluer_noeud(noeud):
if isinstance(noeud, ast.Constant):
return noeud.value # un nombre
if isinstance(noeud, ast.BinOp):
gauche = evaluer_noeud(noeud.left)
droite = evaluer_noeud(noeud.right)
return OPERATIONS[type(noeud.op)](gauche, droite)
if isinstance(noeud, ast.UnaryOp) and isinstance(noeud.op, ast.USub):
return -evaluer_noeud(noeud.operand)

Ecris une fonction calculer(expression) qui prend une expression mathematique sous forme de string et renvoie le resultat numerique. Elle ne doit accepter que des nombres et les operations +, -, *, /, **. Si l'expression est invalide ou contient autre chose (appels de fonction, variables...), elle doit renvoyer un dictionnaire {"error": "Expression invalide"}.

Exemple :

calculer("2 + 3 * 4") renvoie 14
calculer("(10 - 2) ** 2") renvoie 64
calculer("100 / 3") renvoie 33.333...
calculer("import os") renvoie {"error": "Expression invalide"}

Tests (4/5)

Operations de base
assert calculer("2 + 3") == 5
assert calculer("10 - 4") == 6
assert calculer("3 * 7") == 21
assert calculer("15 / 4") == 3.75
Priorite des operations et parentheses
assert calculer("2 + 3 * 4") == 14, "La multiplication doit etre prioritaire"
assert calculer("(2 + 3) * 4") == 20, "Les parentheses doivent etre respectees"
assert calculer("2 ** 3") == 8, "La puissance doit fonctionner"
Nombres negatifs
r = calculer("-5 + 3")
assert r == -2, f"Attendu -2, obtenu {r}"
r2 = calculer("-(2 + 3)")
assert r2 == -5, f"Attendu -5, obtenu {r2}"
Expressions invalides
r = calculer("import os")
assert isinstance(r, dict) and "error" in r, "Une expression invalide doit retourner un dict avec 'error'"
r2 = calculer("print('hello')")
assert isinstance(r2, dict) and "error" in r2
r3 = calculer("abc + 1")
assert isinstance(r3, dict) and "error" in r3

+ 0 tests cachés

Indices (3 disponibles)

solution.py