Как передать параметры функции при использовании timeit.Timer()
Это схема простой программы
# 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
import timeit
t = timeit.Timer(stmt="foo(num1,num2)")
print t.timeit(5)
Я просто продолжаю получать "глобальное имя foo не определено".....
Может ли кто-нибудь помочь мне в этом? Спасибо!
Ответы
Ответ 1
Фрагменты кода должны быть самодостаточными - они не могут создавать внешние ссылки. Вы должны определить свои значения в строке-строке или установочной строке:
import timeit
setup = """
A = 1
B = 2
def foo(num1, num2):
pass
def mainprog():
global A,B
for i in range(20):
# do something to A and B
foo(A, B)
"""
t = timeit.Timer(stmt="mainprog()" setup=setup)
print(t.timeit(5))
Еще лучше, перепишите свой код, чтобы не использовать глобальные значения.
Ответ 2
Функции могут использовать аргументы в timeit
, если они создаются с помощью закрытий, мы можем добавить это поведение, обернув их в другую функцию.
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)
или короче, мы можем использовать functools.partial вместо объявления о явном закрытии
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)
Ответ 3
Предположим, что имя вашего модуля - test.py
# some pre-defined constants
A = 1
B = 2
# function that does something critical
def foo(n, m):
pass
# main program.... do something to A and B
for i in range(20):
pass
import timeit
t = timeit.Timer(stmt="test.foo(test.A, test.B)", setup="import test")
print t.timeit(5)
Ответ 4
Ваша функция должна быть определена в строке настройки. Хороший способ сделать это - настроить код в модуле, поэтому вам просто нужно сделать
t = timeit.Timer("foo(num1, num2)", "from myfile import foo")
t.timeit(5)
В противном случае вам нужно будет определить всю настройку в виде строки внутри инструкции установки.
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)
Что-то удивительное, о котором я только что узнал, это ярлык для iPython, который использует cProfile.
def foo(x, y):
print x*y
%prun foo("foo", 100)
Ответ 5
Я обычно создаю дополнительную функцию:
def f(x,y):
return x*y
v1 = 10
v2 = 20
def f_test():
f(v1,v2)
print(timeit.timeit("f_test()", setup="from __main__ import f_test"))
Ответ 6
Вот пример того, как разделять процедуру синхронизации, не вызывая глобальные переменные
def foo(a, b):
'''Do something to `a` and `b`'''
return a + b
def time_foo():
'''Create timer object simply without using global variables'''
import timeit
_foo = foo
a = 1
b = 2
# Get `Timer` oject, alternatively just get time with `timeit.timeit()`
t = timeit.Timer('_foo(a, b)', globals=locals())
return t
Вы даже можете обобщить это, если хотите использовать ту же функцию timeit
для выполнения других функций. Ниже приведен пример с примером main()
:
def foo1(a, b):
'''Add `a` and `b`'''
return a + b
def foo2(a, b):
'''More math on `a` and `b`'''
return (a**2 * b)**2
def time_foo(func, **kwargs):
'''Create timer object simply without using global variables'''
import timeit
return timeit.timeit('func(**kwargs)', globals=locals())
def run():
'''Modify inputs to foo and see affect on execution time'''
a = 1
b = 2
for i in range(10):
# Update `a` and `b`
a += 1
b += 2
# Pass args to foo as **kwargs dict
print('foo1 time: ', time_foo(foo1, **{'a':a, 'b':b}))
print('foo2 time: ', time_foo(foo2, **{'a':a, 'b':b}))
return None
Ответ 7
Существует гораздо более простое решение (по крайней мере для Python 3), вы можете заставить код выполняться в вашем текущем глобальном пространстве имен:
t = timeit.Timer(stmt="foo(num1,num2)", globals=globals())
https://docs.python.org/3/library/timeit.html#examples
Я знаю, что глобальные переменные не являются предпочтительными, но если вы просто делаете быстрый сценарий для проверки чего-либо, я думаю, что это самая простая реализация.
Ответ 8
Я предпочитаю создавать класс static
со всеми данными, готовыми к загрузке до запуска таймера.
Еще одно замечание: лучше делать тестовые прогоны в функции, а не в глобальном пространстве, поскольку глобальное пространство не использует FAST_LOAD
Почему выполняется код Python быстрее в функции?
class Data(object):
"""Data Creation"""
x = [i for i in range(0, 10000)]
y = tuple([i for i in range(0, 10000)])
def __init__(self):
pass
import timeit
def testIterator(x):
for i in range(10000):
z = i
print timeit.timeit("testIterator(Data.x)", setup="from __main__ import testIterator, Data", number=50)
print timeit.timeit("testIterator(Data.y)", setup="from __main__ import testIterator, Data", number=50)
Ответ 9
Это должно работать:
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))
Ответ 10
Сегодня я играл с синхронизацией в Python 3.7 и пытался передать функции и переменные в таймер. Это то, что я придумал.
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")
Это выводит:
регулярное выражение: 1.378352418
Это тест системы аварийного вещания
loop_ while: 0.15858950299999997
Это тест чрезвычайной ситуации система вещания
Тогда все, что нужно для тестирования новой версии - это добавление новой функции. Что-то вроде:
def split_join(text):
return " ".join(text.split())
Теперь выводит:
регулярное выражение: 1.378352418
Это тест системы аварийного вещания
loop_ while: 0.15858950299999997
Это тест системы аварийного вещания
split_join: 0.05700970800000005
Это тест системы аварийного вещания
Ответ 11
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)