I'm working on a calculator in python. Introductory college course, so I know some stuff, but I'm far from being an expert of any sorts.

This is a scientific/graphing calculator, so I'm parsing a whole string of input.

Say the user inputs integ(3*x+3,0,1) (integrate 3x+3 from 0 to 1). My integration function wants parameters f, a, and b. How do I make eval call integ(), passing the variable x, without trying to see x as a variable? Considering this is a calculator, I'm expecting the possibility of long convoluted input crap such as diff(integ(3*x+3,0,1)*x+5,5)*(3*5)/4 (diff being the differentiate function)

I've ready plenty about calling functions and such with eval. Basically my question is, how do I call a function with eval() and pass it variable parameters?
Code snippets follow.

evalvars = {}
evalvars['integ'] = integ

def integ(funct,a,b):
def f(x):
return map(lambda x: eval(funct),x)
return gauss(a,b,f) #function I wrote for gaussian quadrature integration

def evaluate():
equation = entry.get() #raw input from entry box

When I run this with raw input 'integ(3*x+5,0,1)' I get NameError: name 'x' is not defined

Alternatively, if you have any helpful hints for parsing user input into function calls, it would be very helpful. This is turning out to be the hardest part of this little graphing calculator I'm making. (what a surprise)

## Featured Replies in this Discussion

• ... I tried to play with this code, which evaluates expressions in a fixed namespace, where symbols are added on demand. The function evaluator() take an expression as an argument and returns a function where the unknown variables are ordered alphabetically (for example x and y) ... For a more complete solution, you should have a look in the ast module. The ast.parse function parses a python expression and returns an abstract syntax tree. You…
Post Contains: Quotes Code
• For example, using this code snippet ... and the ast module, I obtain the following graph for the parsing of an expression ... from the nodes Name and BinOp and Call, you should be able to obtain the variable names and the function names, and define your own evaluator for the parsed expression. (Remark: in a graphviz representation, the children of a node are not ordered)

You could write

def evaluator(funct, name='funct'):
code = compile(funct, name,  'eval')
def f(x):
return eval(code, locals())
f.__name__ = name
return f

def integ(funct,a,b):
return gauss(a, b, evaluator(funct))

print integ("3*x++5", 0, 1)

because the expression is evaluated in a dictionary where there is a variable named x (the locals() dict of the function f() above).

Ah, you just edited your code for a question I was going to ask.

Now, looking at that, how do I make it deal with nested functions? Or how do I parse the input to extract the nested functions?

Ah, you just edited your code for a question I was going to ask.

Now, looking at that, how do I make it deal with nested functions? Or how do I parse the input to extract the nested functions?

what do you mean by nested functions ?

what do you mean by nested functions ?

diff(integ(log(anotherCalculatorFunction())))

if I run diff() the way it's written, then it'll try to compile(integ(log(...))) and then eval() it. Unless I'm missing something obvious, it'll choke on this, right?

diff(integ(log(anotherCalculatorFunction())))

if I run diff() the way it's written, then it'll try to compile(integ(log(...))) and then eval() it. Unless I'm missing something obvious, it'll choke on this, right?

I tried to play with this code, which evaluates expressions in a fixed namespace, where symbols are added on demand. The function evaluator() take an expression as an argument and returns a function where the unknown variables are ordered alphabetically (for example x and y)

from math import sqrt

EVAL_NAMESPACE = dict()

def varnames(function):
return func.func_code.co_varnames

def evaluator(expression):
namespace = EVAL_NAMESPACE
code = compile(expression, 'expression', 'eval')
args = []
for name in (n for n in code.co_names if not n in EVAL_NAMESPACE):
if name in globals():
EVAL_NAMESPACE[name] = globals()[name]
else:
args.append(name)
args = tuple(sorted(args))
func = """
def function(%s):
return eval(code, namespace, locals())
""" % (", ".join(args))
exec func in locals()
function.__name__ = "evaluator(%s)" % repr(expression)
print "EVALUATOR:", function.__name__
return function

def foo(expression, a, b):
func = evaluator(expression)
return (func(a) + func(b)) * 0.5

def bar(expression, x):
func = evaluator(expression)
return func(x+1) - func(x)

def evaluate(expression, *args):
return evaluator(expression)(*args)

expr = 'foo("x**2 + x", bar("3*x+2", 2), 1)'
print evaluate(expr)

print evaluate("sqrt(evaluate('x**2+y**2', 3, 8))")

For a more complete solution, you should have a look in the ast module. The ast.parse function parses a python expression and returns an abstract syntax tree. You could examine this tree and build your evaluator on this tree.

For example, using this code snippet http://www.daniweb.com/code/snippet323792.html and the ast module, I obtain the following graph for the parsing of an expression

import ast

node = ast.parse("diff(integ(x**2+y**2, 3, 2), 2)")

def rec_traverse(node):
for n in ast.iter_child_nodes(node):
yield node, n
for item in rec_traverse(n):
yield item

def label(node):
return node.__class__.__name__

from fastgraph import graph
graph(rec_traverse(node), label).draw("graph.png", prog="dot")
import webbrowser
webbrowser.open("graph.png")

from the nodes Name and BinOp and Call, you should be able to obtain the variable names and the function names, and define your own evaluator for the parsed expression. (Remark: in a graphviz representation, the children of a node are not ordered)

Attachments

I tried to play with this code, which evaluates expressions in a fixed namespace, where symbols are added on demand. The function evaluator() take an expression as an argument and returns a function where the unknown variables are ordered alphabetically (for example x and y)

from math import sqrt

EVAL_NAMESPACE = dict()

def varnames(function):
return func.func_code.co_varnames

def evaluator(expression):
namespace = EVAL_NAMESPACE
code = compile(expression, 'expression', 'eval')
args = []
for name in (n for n in code.co_names if not n in EVAL_NAMESPACE):
if name in globals():
EVAL_NAMESPACE[name] = globals()[name]
else:
args.append(name)
args = tuple(sorted(args))
func = """
def function(%s):
return eval(code, namespace, locals())
""" % (", ".join(args))
exec func in locals()
function.__name__ = "evaluator(%s)" % repr(expression)
print "EVALUATOR:", function.__name__
return function

def foo(expression, a, b):
func = evaluator(expression)
return (func(a) + func(b)) * 0.5

def bar(expression, x):
func = evaluator(expression)
return func(x+1) - func(x)

def evaluate(expression, *args):
return evaluator(expression)(*args)

expr = 'foo("x**2 + x", bar("3*x+2", 2), 1)'
print evaluate(expr)

print evaluate("sqrt(evaluate('x**2+y**2', 3, 8))")

For a more complete solution, you should have a look in the ast module. The ast.parse function parses a python expression and returns an abstract syntax tree. You could examine this tree and build your evaluator on this tree.

This is really awesome, thanks. I was getting close with a combination of compile, exec, and eval, but this is really helpful. I'll definitely be looking into the ast module.

One question:

def evaluate(expression, *args):
return evaluator(expression)(*args)

I understand abstractly that *args is passing the sequence args as (positional?) arguments, but how does it work/what is it called? I've been searching for this in Python docs, but there are a lot of syntaxes with asterisks.

This is really awesome, thanks. I was getting close with a combination of compile, exec, and eval, but this is really helpful. I'll definitely be looking into the ast module.

One question:

def evaluate(expression, *args):
return evaluator(expression)(*args)

I understand abstractly that *args is passing the sequence args as (positional?) arguments, but how does it work/what is it called? I've been searching for this in Python docs, but there are a lot of syntaxes with asterisks.

It's described in the syntax of function calls in the python documentation http://docs.python.org/reference/expressions.html#calls

Question Answered as of 4 Years Ago by Gribouillis
You