2009-02-27 33 views
33

¿Cómo puedo (fácilmente) tomar una cadena como "sin(x)*x^2" que un usuario podría ingresar en el tiempo de ejecución y producir una función de Python que podría evaluarse para cualquier valor de x?Análisis de ecuaciones en Python

Respuesta

46

El propio compilador interno de Python puede analizar esto, si usa la notación de Python.

Si cambia ligeramente la notación, será más feliz.

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

Obtiene un árbol de sintaxis abstracto con el que puede trabajar.

+1

¿Se puede agregar un código de muestra sobre cómo usar la función derivada? – Don

+2

@Don: No necesita usar el árbol de sintaxis. Usa la función original. 'eval (" sin (x) * x ** 2 ")' después de establecer 'x' y usar' de math import * '. –

+1

eval() funciona, pero la respuesta no resuelve realmente el problema :( –

0

Sage está destinado como reemplazo de Matlab y en intro videos se demuestra cómo se manejan casos similares a los suyos. Parecen apoyar una amplia gama de enfoques. Como el código es de código abierto, puede navegar y ver por usted mismo cómo manejan los autores dichos casos.

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

Dónde parser podría definirse usando PLY, pyparsing, tokenizer incorporado, analizador, ast.

No utilice eval en la entrada del usuario.

+4

'eval' en la entrada del usuario es realmente malo. – igaurav

2

Para enfatizar los consejos de J.F. Sebastian, 'eval' e incluso las soluciones de 'compilador' pueden abrirse a sutiles problemas de seguridad. ¿Qué tan confiable es la entrada? Con 'compilador' al menos puedes filtrar cosas como búsquedas getattr del AST, pero he descubierto que es más fácil usar PLY o pyparsing para este tipo de cosas que asegurar el resultado de dejar que Python te ayude.

Además, 'compilador' es torpe y difícil de usar. Está en desuso y eliminado en 3.0. Debe usar el módulo 'ast' (agregado en 2.6, disponible en 2.5 como '_ast').

1

De acuerdo con vartec. Yo usaría SymPy, en particular, la función lambdify debería hacer exactamente lo que usted quiere.

Ver: http://showmedo.com/videotutorials/video?name=7200080&fromSeriesID=720

para una muy agradable explicación de esto.

mejores deseos,

+1

Incluya toda la información relevante en la publicación en sí, * "Aquí hay un enlace a un video que responde a la pregunta" * no es una buena respuesta. –

22

Puede usar Python parser:

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

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

Se comporta mejor que pura eval y, por supuesto, evita la inyección de código!

+5

Una cosa importante a tener en cuenta es que usar 'eval()' puro en la entrada del usuario puede ser [** muy peligroso **] (https://stackoverflow.com/questions/1832940/is-using-eval-in-python -a-bad-practice/1832957 # 1832957). –

+0

¿Cómo evita esto la inyección de código? – devxeq

+0

@devxeq Quiero decir que no aceptará cosas tales como 'formula =" os.system ('format C:') "' :) – Don