使用timeit时如何传递函数的参数.Timer()

Cpp*_*ner 41 python 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)
Run Code Online (Sandbox Code Playgroud)

我只是不断得到"全球名称foo没有定义".....任何人都可以帮助我吗?谢谢!

Jos*_* M. 43

函数可以使用参数,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)
Run Code Online (Sandbox Code Playgroud)

或者更短,我们可以使用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)
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,functools帮助我避免了全局,讨厌的字符串方法和装饰/关闭业务. (3认同)
  • 谢谢,这正是我想要的!还应该注意,您甚至不需要实例化“ Timer”;这也有效:```timeit.timeit(functools.partial(foo,A,B),number = 5)``` (2认同)
  • 对于当前的 CPython3.8,与“timeit”的“functools.partial(foo, A, B)”相比,调用“lambda: foo(A, B)”是个坏主意`? (2认同)

Hug*_*ell 15

代码片段必须是自包含的 - 它们不能进行外部引用.您必须在statement-string或setup-string中定义值:

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))
Run Code Online (Sandbox Code Playgroud)

更好的是,重写代码以不使用全局值.

  • Lucas S.回答让这个人觉得有点不对劲.至少尴尬. (4认同)

Luc*_* S. 15

假设您的模块文件名是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)
Run Code Online (Sandbox Code Playgroud)


Yuj*_*ita 9

您的功能需要在设置字符串中定义.执行此操作的一种好方法是在模块中设置代码,这样您就可以轻松完成

t = timeit.Timer("foo(num1, num2)", "from myfile import foo")
t.timeit(5)
Run Code Online (Sandbox Code Playgroud)

否则,您必须将所有设置定义为setup语句中的字符串.

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)
Run Code Online (Sandbox Code Playgroud)

我刚刚发现的一个很棒的东西是使用cProfile的iPython的快捷方式.

def foo(x, y):
    print x*y

%prun foo("foo", 100)
Run Code Online (Sandbox Code Playgroud)


小智 8

我通常创建一个额外的功能:

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"))
Run Code Online (Sandbox Code Playgroud)


Rus*_*oms 5

有一个更简单的解决方案(至少对于 Python 3),您可以使代码在您当前的全局命名空间中执行:

t = timeit.Timer(stmt="foo(num1,num2)", globals=globals())

https://docs.python.org/3/library/timeit.html#examples 我知道全局变量不是首选,但是如果您只是制作一个快速脚本来检查某些内容,我认为这是最简单的实现。


小智 5

另一种选择是通过functools将函数绑定到它的参数(类似于 std::bind)。然后您不需要将参数传递给 timeit,由返回的可调用对象functool.partial负责处理:

    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)
Run Code Online (Sandbox Code Playgroud)