On Wed, 26 Jan 2005, Bill Kranec wrote:
> There has been alot of talk on this list about using list comprehensions > lately, and this could be one of those useful places. While I don't > have time to experiment with real code, I would suggest changing your > function to look like: > > steps = [ min_x + i*delta_x for i in range(steps) ] > totalarea = sum([ eval(func_x)*delta_x for x in steps ]) > > Since list comprehensions are significantly faster than while loops, > this could be a big speed boost. > > There may be a mistake or two in the above code, but hopefully the idea > will be helpful. Calling eval() there in the inner loop might be costly, because Python needs to do extra work to tokenize and parse the string, every time through the iteration. We want to reduce the work done in tight inner loops like that. We can do some of that work up front by compiling the code. Here's some hacky code to do the compilation up front: ### >>> def makeFunction(expressionString): ... compiledExp = compile(expressionString, 'makeFunction', 'eval') ... def f(x): ... return eval(compiledExp, {}, {'x' : x}) ... return f ... ### Some of the stuff there is a bit obscure, but the idea is that we get Python to parse and compile the expression down once. Later on, we can evaluation the compiled code, and that should be faster than evaluating a string. Once we have this, we can use it like this: ### >>> myFunction = makeFunction("3*x*x") >>> myFunction(0) 0 >>> myFunction(1) 3 >>> myFunction(2) 12 >>> myFunction(3) 27 ### So although makeFunction()'s internals are weird, it shouldn't be too hard to treat it as a black box. *grin* Let's see how this performs against that 3x^2 expression we saw before. The original approach that calls eval() on the string takes time: ### >>> def timeIt(f, n=1000): ... start = time.time() ... for i in xrange(n): ... f(i) ... end = time.time() ... return end - start ... >>> def myFunctionOriginal(x): ... return eval("3*x*x") ... >>> timeIt(myFunctionOriginal) 0.036462068557739258 ### The precompiled expression can work more quickly: ### >>> timeIt(myFunction) 0.0050611495971679688 ### And we should still get the same results: ### >>> for i in range(2000): ... assert myFunction(i) == myFunctionOriginal(i) ... >>> ### I hope this helps! _______________________________________________ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor