On 5/10/2015 5:58 AM, Steven D'Aprano wrote:
Why is calling a function faster than bypassing the function object and
evaluating the code object itself? And not by a little, but by a lot?

Here I have a file, eval_test.py:

# === cut ===
from timeit import Timer

def func():
     a = 2
     b = 3
     c = 4
     return (a+b)*(a-b)/(a*c + b*c)


code = func.__code__
assert func() == eval(code)

t1 = Timer("eval; func()", setup="from __main__ import func")
t2 = Timer("eval(code)", setup="from __main__ import code")

eval has 3 parameters. I believe omitting the last two results in globals() and locals() calls, but at least one of them. If {} is passed, access to builtins is added.

# Best of 10 trials.
print (min(t1.repeat(repeat=10)))
print (min(t2.repeat(repeat=10)))

Adding
g = globals()
t3 = Timer("eval(code, g)", setup="from __main__ import code, g")
print (min(t3.repeat(repeat=10)))

>>>
0.3992733933018515
0.6967548323372563
0.49210603735894587

2/3s of the extra time disappears, but there is still extra time needed for processing the two extra arguments. Passing g twice has no effect

[steve@ando ~]$ python2.7 eval_test.py
0.804041147232
1.74012994766

Directly eval'ing the code object is easily more than twice as expensive
than calling the function, but calling the function has to eval the code

Calling the function executes the code via its .__call__ method.
Perhaps eval wraps the code object in a function object with .__call__. I don't know the comparative internals.


--
Terry Jan Reedy

--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to