I am struggling to make a piece of code that allows to measure time spent within a "with" statement and assigns the time measured (a float) to the variable provided in the "with" statement.
import time
class catchtime:
def __enter__(self):
self.t = time.clock()
return 1
def __exit__(self, type, value, traceback):
return time.clock() - self.t
with catchtime() as t:
pass
This code leaves t=1
and not the difference between clock() calls. How to approach this problem? I need a way to assign a new value from within the exit method.
PEP 343 describes in more detail how contect manager works but I do not understand most of it.
Python timeit module is often used to measure the execution time of small code snippets. We can also use the timeit() function, which executes an anonymous function with a number of executions. It temporarily turns off garbage collection while calculating the time of execution.
A context manager usually takes care of setting up some resource, e.g. opening a connection, and automatically handles the clean up when we are done with it. Probably, the most common use case is opening a file. The code above will open the file and will keep it open until we are out of the with statement.
Example 1: Using time module In order to calculate the time elapsed in executing a code, the time module can be used. Save the timestamp at the beginning of the code start using time() . Save the timestamp at the end of the code end . Find the difference between the end and start, which gives the execution time.
As noted already by @Mercury, the top answer by @Vlad Bezden, while slick, is technically incorrect since the value yielded by t()
is also potentially affected by code executed outside of the with
statement. For example, if you execute time.sleep(5)
after the with
statement but before the print
statement, then calling t()
in the print statement will give you ~6 sec, not ~1 sec.
This can be avoided by doing the print command inside the context manager as below:
from time import perf_counter
from contextlib import contextmanager
@contextmanager
def catchtime() -> float:
start = perf_counter()
yield lambda: perf_counter() - start
# Note: print is included here to guarantee only time of code inside the CM is measured
print(f'Time: {perf_counter() - start:.3f} seconds')
Notice how sleep(5) causes the incorrect time to be printed:
from time import sleep
with catchtime() as t:
sleep(1)
# >>> "Time: 1.000 seconds"
sleep(5)
print(f'Time: {t():.3f} seconds')
# >>> "Time: 6.000 seconds"
This code is similar to the excellent answer given by @BrenBarn execept that it:
print(self.readout)
)self.readout
)float
result for later use (self.time
)from time import perf_counter
class catchtime:
def __enter__(self):
self.time = perf_counter()
return self
def __exit__(self, type, value, traceback):
self.time = perf_counter() - self.time
self.readout = f'Time: {self.time:.3f} seconds'
print(self.readout)
Notice how the intermediate sleep(5)
commands no longer have an effect on the printed time.
from time import sleep
with catchtime() as t:
sleep(1)
# >>> "Time: 1.000 seconds"
sleep(5)
print(t.time)
# >>> 1.000283900000009
sleep(5)
print(t.readout)
# >>> "Time: 1.000 seconds"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With