Подтвердить что ты не робот

Как передать параметры функции при использовании 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 не определено"..... Может ли кто-нибудь помочь мне в этом? Спасибо!

4b9b3361

Ответ 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)