2

How can a random code block be executed in python without resorting to string-ifying it . I am most likely not interested in using eval or exec .

So the use case would be to provide timing of a code block - but not requiring the hack of first converting the code block to a string:

def formatTimeDelta(td):
  return '%d.%d' %(td.total_seconds() , int(td.microseconds/1000))

def timeit(tag, block):
  def getNow(): return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())

  startt = datetime.datetime.now()
  print('Starting %s at %s..' %(tag,getNow()))
  block  # Execute the code!
  duration = formatTimeDelta(datetime.datetime.now() - startt)
  print('Completed %s at %s with duration=%s secs' %(tag,getNow(), duration))

So then we would use something like:

Given a "random" code block

def waitsecs(nsecs):
   import time
   time.sleep(nsecs)
   print('I slept %d secs..' %nsecs)

timeit('wait five secs', (
   waitsecs(5)
))

I believe I had done all this in the past but can not seem to dig it up ..

4
  • I may be missing something, but this pretty much looks like what timeit.Timer is for. For example print(timeit.Timer(func_to_time).repeat(1, 1)) Commented May 22, 2019 at 13:06
  • The example i see is using strings .. timeit.Timer('for i in xrange(10): oct(i)', 'gc.enable()').timeit() . If you see a usage with Timer that takes real code please do point it out. Commented May 22, 2019 at 13:09
  • timeit.Timer also accepts a callable, see my example Commented May 22, 2019 at 13:09
  • ah ok I see in source code the argument can be either a string or a callable. pls make an answer Commented May 22, 2019 at 13:10

4 Answers 4

4

timeit.Timer does exactly that.

from time import sleep
from timeit import Timer

print(Timer(lambda: sleep(5)).repeat(1, 1))
# [5.000540999999999]

repeat is just one way to time the function, read the linked docs for other available methods.

Sign up to request clarification or add additional context in comments.

4 Comments

I tried to understand from the source code timeit.py how the Callable were being handled but did not "get" it. If you were able to shed some light that would be a bonus.
The stmt and setup parameters can also take objects that are callable without arguments I probably read that once (or twice, ...) and immediately forgot it.
@javadba timeit.Timer.__init__ does a very explicit check: elif callable(stmt):
Yes I saw that but I'm trying to go deeper and understand how the stmt / code block actually gets invoked . It should not be a eval or exec .. so what is the mechanism?
1

The easiest method I've found is using the magic command %timeit in ipython or Jupyter notebook. You can specify the number of repetitions and loops if you want:

$ ipython                                                                                                           

In [1]: import time

In [2]: %timeit -n1 -r1 time.sleep(5)
5 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)

In [3]: %timeit [i**2 for i in range(10000)]
8.12 ms ± 14.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

You don't need any lambda, any defined function or any stringified code.

1 Comment

Thx - I have mostly moved away from notebooks except for display purposes and do heavy lifting in pycharm . In any case will upvote as it does answer the question for notebook env's.
0

You can send callable to timeit.timeit() function, but only if it has no attributes. If it has any attributes, you should use setup-code.

timeit.timeit() function has setup attribute. You can send a code (but still stringified) to "eval" it before timeit Timer object starts to work. Here is the example:

import timeit

s = """
import math

def waka(number):
    return math.sqrt(number)
"""

timeit.timeit('waka(100)', setup=s)

It is how timeit.timeit() works:

Create a Timer instance with the given statement, setup code and timer function and run its timeit() method with number executions. The optional globals argument specifies a namespace in which to execute the code.

1 Comment

point of the question was to avoid using strings for the code to be timed.
0

Use a decorator, for example: @timeit decorator:

def timeit(method):
    def timed(*args, **kw):
        ts = time.time()
        result = method(*args, **kw)
        te = time.time()
        if 'log_time' in kw:
            name = kw.get('log_name', method.__name__.upper())
            kw['log_time'][name] = int((te - ts) * 1000)
        else:
            print '%r  %2.2f ms' % \
                  (method.__name__, (te - ts) * 1000)
        return result
    return timed

Adding decorator to the method:

@timeit
def get_all_employee_details(**kwargs):
    print 'employee details'

Taken from: https://medium.com/pythonhive/python-decorator-to-measure-the-execution-time-of-methods-fa04cb6bb36d

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.