how to pass parameters of a function when using timeit.Timer()

前端 未结 12 1732
礼貌的吻别
礼貌的吻别 2020-12-02 10:19

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         


        
相关标签:
12条回答
  • 2020-12-02 11:03

    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))
    
    0 讨论(0)
  • 2020-12-02 11:04

    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 system

    loop_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 system

    loop_while: 0.15858950299999997
    This is a test of the emergency broadcast system

    split_join: 0.05700970800000005
    This is a test of the emergency broadcast system

    0 讨论(0)
  • 2020-12-02 11:05

    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)
    
    0 讨论(0)
  • 2020-12-02 11:07

    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)
    
    0 讨论(0)
  • 2020-12-02 11:11

    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))
    
    0 讨论(0)
  • 2020-12-02 11:12

    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))
    
    0 讨论(0)
提交回复
热议问题