5

I'm just playing around in python with timeit and the following code works properly:

def mysleep(n):
    import time
    time.sleep(n)

import timeit
for k in range (1,5):
    def mytime():
        mysleep(k)
    t1 = timeit.Timer("mytime();", "from __main__ import mytime") 
    print k, t1.timeit(1)  

But if I put the same code inside a function, for each k the time is about 3 seconds.

def mytest(): 
    import timeit
    for k in range (1,5):
        def mytime():
            mysleep(k)
        t1 = timeit.Timer("mytime();", "from __main__ import mytime") 
        print k, t1.timeit(1)  

mytest()

Why doesn't my code inside a function work and how can I fix it?

Anna
  • 163
  • 1
  • 5
  • 1
    `from __main__ import time` cannot import your nested function object, as it doesn't live at the global level. If you have a global `time` object *as well* it'll be timing that, not the nested function. – Martijn Pieters Jul 31 '14 at 12:46
  • 1
    Why the downvotes? I don`t see why the question is ill posed. The fact, that this is a beginner question is no reason to downvote it. So if you have good reasons, please leave a comment so that I can improve it. – Anna Jul 31 '14 at 12:52
  • @MartijnPieters Thanks. What would you suggest to make it work? – Anna Jul 31 '14 at 12:54
  • You may have got the down-vote for defining a function with the same name as a standard module and another with the same name as a function inside that module. – martineau Jul 31 '14 at 15:44

1 Answers1

2

Your setup statement imports mytime() from your module globals, but you defined the function-to-test in your function locals. As such the setup statement will either fail (if you don't have a global mytime() function as well) or import the wrong object.

In your case, you must've also had a global mytime() function still that takes 3 seconds to run each time you call it.

timeit.Timeit() can also take callables as arguments instead of strings; pass in the mytime() function directly:

def mytest(): 
    import timeit
    for k in range (1,5):
        def mytime():
            mysleep(k)
        t1 = timeit.Timer(mytime) 
        print k, t1.timeit(1)  

Now there is no need to import the object. This only works for callables that take no arguments, and using a function like this adds a small overhead to all timed calls.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Thanks. Do I understand it correctly, that defining `time` to get a function with no arguments which I can pass to `timeit` is really necessary. So there is no way to pass `sleep(k)` directly to `timeit` in this case? – Anna Jul 31 '14 at 13:07
  • 1
    @Anna: no, there is not, because `Timeit()` cannot be passed Python code that can access the local function object. – Martijn Pieters Jul 31 '14 at 13:12
  • I've changed the names of the functions in your answer, becauce i've changed them in my question. I hope this is ok. If not feel free to roll it back. – Anna Jul 31 '14 at 16:32