2009-02-27 13 views
33

Come posso (facilmente) prendere una stringa come "sin(x)*x^2" che potrebbe essere immessa da un utente in fase di esecuzione e produrre una funzione Python che potrebbe essere valutata per qualsiasi valore di x?Analisi delle equazioni in Python

risposta

46

Il compilatore interno di Python può analizzarlo, se si utilizza la notazione Python.

Se cambi leggermente la notazione, sarai più felice.

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

Si ottiene un albero di sintassi astratto con cui si può lavorare.

+1

È possibile aggiungere un codice di esempio su come utilizzare la funzione derivata? – Don

+2

@Don: non è necessario utilizzare l'albero di sintassi. Usa la funzione originale. 'eval (" sin (x) * x ** 2 ")' dopo aver impostato 'x' e usando' dall'importazione matematica * '. –

+1

eval() funziona, ma la risposta in realtà non risolve il problema :( –

0

Sage è inteso come sostituzione MATLAB e in intro videos è dimostrato come vengono gestiti i casi simili. Sembrano supportare una vasta gamma di approcci. Dato che il codice è open source, puoi sfogliare e vedere di persona come gli autori gestiscono tali casi.

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

Dove parser potrebbe essere definito utilizzando PLY, pyparsing, tokenizzatore incorporata, parser, ast.

Non utilizzare eval per l'input dell'utente.

+4

"eval' sull'input dell'utente è davvero negativo. – igaurav

2

Per enfatizzare il consiglio di J.F. Sebastian, le soluzioni "eval" e persino quelle del "compilatore" possono essere aperte a sottili buchi di sicurezza. Quanto è affidabile l'input? Con 'compiler' puoi almeno filtrare cose come getattr lookup da AST, ma ho trovato che è più facile usare PLY o pyparsing per questo genere di cose piuttosto che garantire il risultato di lasciare che Python aiuti.

Inoltre, "compilatore" è maldestro e difficile da utilizzare. È deprecato e rimosso in 3.0. Dovresti usare il modulo 'ast' (aggiunto in 2.6, disponibile in 2.5 come '_ast').

1

In accordo con vartec. Vorrei usare SymPy - in particolare la funzione lambdify dovrebbe fare esattamente quello che vuoi.

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

per una bella spiegazione di questo.

migliori auguri,

+1

Si prega di includere tutte le informazioni rilevanti nel post stesso, * "Ecco un link a un video che risponde alla domanda" * non è una buona risposta. –

22

È possibile utilizzare Python parser:

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

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

Si comporta meglio di pura eval e, naturalmente, evita l'iniezione di codice!

+5

Una cosa importante da notare è che l'uso puro di 'eval()' sull'input dell'utente può essere [** molto pericoloso **] (https://stackoverflow.com/questions/1832940/is-using-eval-in-python -a-bad-pratica/1832957 # 1832957). –

+0

Come si evita l'iniezione di codice? – devxeq

+0

@devxeq Voglio dire che non accetterà cose come 'formula =" os.system ('formato C:') "' :) – Don

Problemi correlati