web-dev-qa-db-fra.com

Analyse d'équations dans Python

Comment puis-je (facilement) prendre une chaîne telle que "sin(x)*x^2" qui pourrait être entrée par un utilisateur au moment de l'exécution et produire une fonction Python qui pourrait être évaluée pour n'importe quelle valeur de x?

39
WalkingRandomly

Le propre compilateur interne de Python peut analyser cela, si vous utilisez la notation Python.

Si vous modifiez légèrement la notation, vous serez plus heureux.

import compiler
eq= "sin(x)*x**2"
ast= compiler.parse( eq )

Vous obtenez un arbre de syntaxe abstrait avec lequel vous pouvez travailler.

46
S.Lott

Vous pouvez utiliser Python parser:

import parser
formula = "sin(x)*x**2"
code = parser.expr(formula).compile()

from math import sin
x = 10
print eval(code)

Il fonctionne mieux que le pur eval et, bien sûr, évite l'injection de code!

31
Don
 f = parser.parse('sin(x)*x^2').to_pyfunc()

parser pourrait être défini à l'aide de PLY, de la mise en forme, du tokenizer intégré, de l'analyseur, de ast.

N'utilisez pas eval sur les entrées utilisateur.

14
jfs

pyparsing peut faire ce que vous voulez ( http://pyparsing.wikispaces.com/ ) surtout si les chaînes proviennent d'une source non fiable.

Voir aussi http://pyparsing.wikispaces.com/file/view/fourFn.py pour une calculatrice assez complète construite avec elle.

7
cryo

Pour souligner les conseils de J.F. Sebastian, les solutions 'eval' et même 'compiler' peuvent être ouvertes à de subtiles failles de sécurité. Quelle est la fiabilité de l'entrée? Avec le `` compilateur '', vous pouvez au moins filtrer des choses comme les recherches getattr de l'AST, mais j'ai trouvé qu'il est plus facile d'utiliser PLY ou le pyparsing pour ce genre de chose que de sécuriser le résultat de laisser Python aidez.

De plus, le "compilateur" est maladroit et difficile à utiliser. Il est obsolète et supprimé dans 3.0. Vous devez utiliser le module 'ast' (ajouté en 2.6, disponible en 2.5 en tant que '_ast').

2
Andrew Dalke

En accord avec vartec. J'utiliserais SymPy - en particulier la fonction lambdify devrait faire exactement ce que vous voulez.

Voir: http://showmedo.com/videotutorials/video?name=7200080&fromSeriesID=72

pour une très belle explication de cela.

Meilleurs vœux,

1
Geddes

Sage est destiné au remplacement de matlab et dans vidéos d'introduction il est démontré à quel point les cas similaires aux vôtres sont traités. Ils semblent soutenir un large éventail d'approches. Étant donné que le code est open-source, vous pouvez parcourir et voir par vous-même comment les auteurs traitent de tels cas.

0
SilentGhost