Re: newbie: generate a function based on an expression
Thanks for all the suggestions and comments!! I will try all those suggestions just to I can figure out how they work. For phase 1 of this project, I will probably go with the eval. thanks again, happy hacking... jr -- http://mail.python.org/mailman/listinfo/python-list
Re: newbie: generate a function based on an expression
Overall I am trying to learn OOP by porting CppSim (http://www-mtl.mit.edu/~perrott) to Python. In CppSim, classes are defined that allow various functions to be defined, like amplifiers. In some cases they are linear: y = A*x some have offsets: y = A*x + off some are non-linear y = A*x - C*x**3 The coefficients and the function will remain constant once the function is defined. I read about the security concerns involved in using eval(). I don't expect this project to grow to the point where I require a web interface. However, since I am learning, I might as well learn the right way. -- http://mail.python.org/mailman/listinfo/python-list
Re: newbie: generate a function based on an expression
Another example is a filter. From the CppSim doc: Filter filt(1+1/(2*pi*fz)s,C3*s + C3/(2*pi*fp)*s^2,C3,fz,fp,Ts,1/gain,fz,fp,Ts); jr -- http://mail.python.org/mailman/listinfo/python-list
Re: newbie: generate a function based on an expression
Jacob Rael [EMAIL PROTECTED] writes: I read about the security concerns involved in using eval(). I don't expect this project to grow to the point where I require a web interface. However, since I am learning, I might as well learn the right way. I think you're going to have to write an actual parser and evaluator. There are various tools that can help you do that (PyParse, etc.) but if it's for a learning project, you might like to try doing it from scratch. -- http://mail.python.org/mailman/listinfo/python-list
Re: newbie: generate a function based on an expression
Jacob Rael [EMAIL PROTECTED] writes: In CppSim, classes are defined that allow various functions to be defined, like amplifiers. In some cases they are linear: y = A*x some have offsets: y = A*x + off some are non-linear y = A*x - C*x**3 The coefficients and the function will remain constant once the function is defined. It appears that CppSim is a language, including parsers, evaluators, and the other things that a language processor usually has. To do a proper port of it, you'll have to recreate all that mechanism. On the other hand, if you want CppSim-like program with pythonesque expressions written in Python, then eval is probably the best way to go - if you can live with the security concerns. An example of this is my P(x) package, as it relates to the original F(x) package. P(x) programs have all the power of Python, and so deserve to be treated with the same suspicion you'd treat a Python program. I read about the security concerns involved in using eval(). I don't expect this project to grow to the point where I require a web interface. However, since I am learning, I might as well learn the right way. Web interfaces are just one source of suspect data. That's the common one, because that allows arbitrary users to submit data. But it's not uncommon to not trust data from other sources as well. In this case, you really want to let users write general-purpose functions. The non-eval way to do that is to use closures and higher order functions, but that's not going to look much like cppSim. mike -- Mike Meyer [EMAIL PROTECTED] http://www.mired.org/home/mwm/ Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information. -- http://mail.python.org/mailman/listinfo/python-list
Re: newbie: generate a function based on an expression
On 12 Dec 2005 21:38:23 -0800, Jacob Rael [EMAIL PROTECTED] wrote: Hello, I would like write a function that I can pass an expression and a dictionary with values. The function would return a function that evaluates the expression on an input. For example: fun = genFun(A*x+off, {'A': 3.0, 'off': -0.5, 'Max': 2.0, 'Min': -2.0} ) fun(0) -0.5 fun(-10) -2 fun(10) 2 so fun would act as if I did: def fun(x): A = 3 off = -0.5 Max = 2 Min = -2 y = min(Max,max(Min,A*x + off)) return(y) Any ideas? ISTM genFun above can't generate fun without special interpretation of Min and Max. I.e., how is it supposed to know to use min and max (lower case) as in your expression for y, unless you tell it to by writing fun = genFun(min(Max,max(Min,A*x+off)), {'A': 3.0, 'off': -0.5, 'Max': 2.0, 'Min': or state a rule about using min and/or max when Max and/or Min are present? Setting aside security for the moment, and guessing at the rule you might want for Min and Max, perhaps something like (untested beyond what you see): (also limited to using x as the single function parameter name in the expression!) import math allow = dict((k,v) for k,v in vars(math).items() ... if callable(v) and not k.startswith('_') or k in ('e','pi')) allow.update(min=min, max=max) def vetexpr(expr, dct): return expr # XXX generate and check AST later ... def genFun(expr, dct=None): ... d = allow.copy() ... if dct: d.update(dct) ... expr = '('+expr+')' ... vetexpr(expr, d) # check for illegal stuff XXX later ... if 'Min' in d: expr = 'max(Min, %s)'%(expr,) ... if 'Max' in d: expr = 'min(Max, %s)'%(expr,) ... return eval('lambda x: %s'%expr, d) ... fun = genFun(A*x+off, {'A': 3.0, 'off': -0.5, 'Max': 2.0, 'Min': -2.0}) fun function lambda at 0x02EEBDF4 fun(0) -0.5 fun(-10) -2.0 fun(10) 2.0 import dis dis.dis(fun) 1 0 LOAD_GLOBAL 0 (min) 3 LOAD_GLOBAL 1 (Max) 6 LOAD_GLOBAL 2 (max) 9 LOAD_GLOBAL 3 (Min) 12 LOAD_GLOBAL 4 (A) 15 LOAD_FAST0 (x) 18 BINARY_MULTIPLY 19 LOAD_GLOBAL 6 (off) 22 BINARY_ADD 23 CALL_FUNCTION2 26 CALL_FUNCTION2 29 RETURN_VALUE I just made things from the math module accessible in anticipation. E.g., sin2xd = genFun('sin(2.0*x*pi/180.)') sin2xd(15) 0.49994 sin2xd(0) 0.0 sin2xd(45) 1.0 Of course, if the dict is all constant named coefficients, you could substitute them as literal values in the expression before generating the function. You could do that in the placeholder vetexpr, but we'll leave that implementation for another post ;-) Regards, Bengt Richter -- http://mail.python.org/mailman/listinfo/python-list
Re: newbie: generate a function based on an expression
Bengt Richter wrote: On 12 Dec 2005 21:38:23 -0800, Jacob Rael [EMAIL PROTECTED] wrote: Hello, I would like write a function that I can pass an expression and a dictionary with values. The function would return a function that evaluates the expression on an input. For example: fun = genFun(A*x+off, {'A': 3.0, 'off': -0.5, 'Max': 2.0, 'Min': -2.0} ) fun(0) -0.5 fun(-10) -2 fun(10) 2 so fun would act as if I did: def fun(x): A = 3 off = -0.5 Max = 2 Min = -2 y = min(Max,max(Min,A*x + off)) return(y) Any ideas? ISTM genFun above can't generate fun without special interpretation of Min and Max. I.e., how is it supposed to know to use min and max (lower case) as in your expression for y, unless you tell it to by writing fun = genFun(min(Max,max(Min,A*x+off)), {'A': 3.0, 'off': -0.5, 'Max': 2.0, 'Min': or state a rule about using min and/or max when Max and/or Min are present? Setting aside security for the moment, and guessing at the rule you might want for Min and Max, perhaps something like (untested beyond what you see): (also limited to using x as the single function parameter name in the expression!) import math allow = dict((k,v) for k,v in vars(math).items() ... if callable(v) and not k.startswith('_') or k in ('e','pi')) allow.update(min=min, max=max) def vetexpr(expr, dct): return expr # XXX generate and check AST later ... def genFun(expr, dct=None): ... d = allow.copy() ... if dct: d.update(dct) ... expr = '('+expr+')' ... vetexpr(expr, d) # check for illegal stuff XXX later ... if 'Min' in d: expr = 'max(Min, %s)'%(expr,) ... if 'Max' in d: expr = 'min(Max, %s)'%(expr,) ... return eval('lambda x: %s'%expr, d) ... fun = genFun(A*x+off, {'A': 3.0, 'off': -0.5, 'Max': 2.0, 'Min': -2.0}) fun function lambda at 0x02EEBDF4 fun(0) -0.5 fun(-10) -2.0 fun(10) 2.0 import dis dis.dis(fun) 1 0 LOAD_GLOBAL 0 (min) 3 LOAD_GLOBAL 1 (Max) 6 LOAD_GLOBAL 2 (max) 9 LOAD_GLOBAL 3 (Min) 12 LOAD_GLOBAL 4 (A) 15 LOAD_FAST0 (x) 18 BINARY_MULTIPLY 19 LOAD_GLOBAL 6 (off) 22 BINARY_ADD 23 CALL_FUNCTION2 26 CALL_FUNCTION2 29 RETURN_VALUE I just made things from the math module accessible in anticipation. E.g., sin2xd = genFun('sin(2.0*x*pi/180.)') sin2xd(15) 0.49994 sin2xd(0) 0.0 sin2xd(45) 1.0 Of course, if the dict is all constant named coefficients, you could substitute them as literal values in the expression before generating the function. You could do that in the placeholder vetexpr, but we'll leave that implementation for another post ;-) Regards, Bengt Richter Here's another take on the source-composition approach: Setup a useful enviroment: def makenamespace(): Get some useful, and (I hope) safe functions import math, __builtin__ modules = { math:['acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'cosh', 'degrees', 'e', 'exp', 'fabs', 'floor', 'fmod', 'frexp', 'hypot', 'ldexp', 'log', 'log10', 'modf', 'pi', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh'], __builtin__:['max', 'min', 'pow'] } ns = dict((n, getattr(mod, n)) for mod in modules for n in modules[mod]) return ns def compose_source(expr, presets, namespace = makenamespace()): Return a function whose arguments are inferred from expr and whose constants are found in presets func = compile(expr, src, eval) names = func.co_names arguments = ,.join(name for name in names if name not in presets and name not in namespace) sourcelines = \ [def func(%s): % arguments] +\ [%s=%s % (name, value) for name, value in presets.iteritems()] +\ [return %s % expr] composed = \n.join(sourcelines) + \n exec composed in namespace return namespace[func] f = compose_source(min(a * b, max(c* d)),{a: 3, b: 4, c: 5}) f is now a function only of d, since a,b and c are constants: import inspect inspect.formatargspec(inspect.getargspec(f)) '((d,), None, None, None)' f = compose_source(min(a * b, max(c* d)),{d: 3, b: 4, c: 5}) inspect.getargspec(f) -- http://mail.python.org/mailman/listinfo/python-list
newbie: generate a function based on an expression
Hello, I would like write a function that I can pass an expression and a dictionary with values. The function would return a function that evaluates the expression on an input. For example: fun = genFun(A*x+off, {'A': 3.0, 'off': -0.5, 'Max': 2.0, 'Min': -2.0} ) fun(0) -0.5 fun(-10) -2 fun(10) 2 so fun would act as if I did: def fun(x): A = 3 off = -0.5 Max = 2 Min = -2 y = min(Max,max(Min,A*x + off)) return(y) Any ideas? jr -- http://mail.python.org/mailman/listinfo/python-list
newbie: generate a function based on an expression
def genFun(expr, locs): ... return lambda x: eval('min(Max,max(Min,%s))' % expr, locs, {'x': x}) ... fun = genFun(A*x+off, {'A': 3.0, 'off': -0.5, 'Max': 2.0, 'Min': -2.0} ) fun function lambda at 0x011B1470 fun(0) -0.5 fun(-10) -2.0 fun(10) 2.0 -- http://mail.python.org/mailman/listinfo/python-list
Re: newbie: generate a function based on an expression
Jacob Rael wrote: Hello, I would like write a function that I can pass an expression and a dictionary with values. The function would return a function that evaluates the expression on an input. For example: fun = genFun(A*x+off, {'A': 3.0, 'off': -0.5, 'Max': 2.0, 'Min': -2.0} ) fun(0) -0.5 fun(-10) -2 fun(10) 2 so fun would act as if I did: def fun(x): A = 3 off = -0.5 Max = 2 Min = -2 y = min(Max,max(Min,A*x + off)) return(y) Any ideas? jr You might prefer to write your expression as a real function, rather than a source string, so that it would be easier to test. def fun(x, A, off, Max, Min): ... return min(Max,max(Min,A*x + off)) ... Then you can curry in the constant values, using something like: def getFun(fn, env_dict): ... env_dict = env_dict.copy() ... def fun_curry(x): ... return fn(x,**env_dict) ... return fun_curry ... myenv = {'A': 3.0, 'off': -0.5, 'Max': 2.0, 'Min': -2.0} fun1 = getFun(fun, myenv) fun1(0) -0.5 fun1(0.5) 1.0 fun1(-10) -2.0 fun1(10) 2.0 HTH Michael -- http://mail.python.org/mailman/listinfo/python-list
Re: newbie: generate a function based on an expression
Jacob Rael [EMAIL PROTECTED] writes: Hello, I would like write a function that I can pass an expression and a dictionary with values. The function would return a function that evaluates the expression on an input. For example: fun = genFun(A*x+off, {'A': 3.0, 'off': -0.5, 'Max': 2.0, 'Min': -2.0} ) fun(0) -0.5 fun(-10) -2 fun(10) 2 so fun would act as if I did: def fun(x): A = 3 off = -0.5 Max = 2 Min = -2 y = min(Max,max(Min,A*x + off)) return(y) Any ideas? def genFun(expr, ns): ... def fun(x): ... newns = dict(ns) ... newns['x'] = x ... return eval(code, newns) ... code = compile(min(Max, max(Min, %s)) % expr, 'genFun', 'single') ... return fun Having said that, this is a *very* insecure thing to do. If you'd let us know why you want to do this, we might be able to suggest a safer way. mike -- Mike Meyer [EMAIL PROTECTED] http://www.mired.org/home/mwm/ Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information. -- http://mail.python.org/mailman/listinfo/python-list