This is the outline of a simple program
# some pre-defined constants
A = 1
B = 2
# function that does something critical
def foo(num1, num2):
# do somet
The functions can use arguments in timeit
if these are created using closures, we can add this behaviours by wrapping them in another function.
def foo(num1, num2):
def _foo():
# do something to num1 and num2
pass
return _foo
A = 1
B = 2
import timeit
t = timeit.Timer(foo(A,B))
print(t.timeit(5))
or shorter, we can use functools.partial instead of explicit closures declaration
def foo(num1, num2):
# do something to num1 and num2
pass
A = 1
B = 2
import timeit, functools
t = timeit.Timer(functools.partial(foo, A, B))
print(t.timeit(5))
EDIT using lambda, thanks @jupiterbjy
we can use lambda function without parameters instead of functools library
def foo(num1, num2):
# do something to num1 and num2
pass
A = 1
B = 2
import timeit
t = timeit.Timer(lambda: foo(A, B))
print (t.timeit(5))
I was playing around with timing in Python 3.7 today and trying to pass functions and variables into the timer. This is what I came up with.
import re
text = "This is a test of the emergency broadcast system"
def regex(text):
return re.sub(r"(\s)\1{1,}", r"\1", text)
def loop_while(text):
if " " in text:
while " " in text:
text = text.replace(" ", " ")
return text
if __name__ == "__main__":
import timeit
callable_functions = [item for item in locals().items() if callable(item[1])]
for func_name, func in callable_functions:
elapsed_time = timeit.timeit(f"{func_name}(text)", globals=globals(), number=100000)
print(f"{func_name}: {elapsed_time} \n{func(text)}\n")
This outputs:
regex: 1.378352418
This is a test of the emergency broadcast systemloop_while: 0.15858950299999997
This is a test of the emergency broadcast system
Then all it takes to test a new version is adding in a new function. Something like:
def split_join(text):
return " ".join(text.split())
Now it outputs:
regex: 1.378352418
This is a test of the emergency broadcast systemloop_while: 0.15858950299999997
This is a test of the emergency broadcast systemsplit_join: 0.05700970800000005
This is a test of the emergency broadcast system
Another option is to bind the function to its arguments via functools (similar to std::bind). Then you don't need to pass arguments to timeit, the callable returned by functool.partial
takes care of that:
def findMax(n):#n is an array
m = 0
c = 0
for i in range(len(n)):
c += 1
if m < n[i]:
m = n[i]
return m, c
import timeit
import functools
a = [6, 2, 9, 3, 7, 4, 5]
t = timeit.Timer(functools.partial(findMax,a))
t.timeit(100)
Your function needs to be define in the setup string. A good way to do this is by setting up your code in a module, so you simple have to do
t = timeit.Timer("foo(num1, num2)", "from myfile import foo")
t.timeit(5)
Otherwise, you'll have to define all of the setup as a string inside the setup statement.
setup = """
# some pre-defined constants
A = 1
B = 2
# function that does something critical
def foo(num1, num2):
# do something
# main program.... do something to A and B
for i in range(20):
# do something to A and B
# and update A and B during each iteration
"""
t = timeit.Timer("foo(num1, num2)", setup)
t.timeit(5)
Something awesome I just found out about is a shortcut for iPython that uses cProfile.
def foo(x, y):
print x*y
%prun foo("foo", 100)
You have to create the variable within the setup string. Here I import the function, and create one of the variables that i pass to it. I also set one of the variables by casting it to the stmt string
SETUP = '''
from __main__ import policy_iteration
from environments.gridworld import GridworldEnv
env = GridworldEnv()
'''
discount = 5
timeit.timeit("policy_iteration(env,discount_factor="+str(discount)+")",
setup= SETUP,
number=10))
This should work:
import timeit
def f(x,y):
return x*y
x = 5
y = 7
print(timeit.timeit(stmt='f(x,y)',
setup='from __main__ import f, x, y',
number=1000))