Hello and thanks for your help :)
Question
My question is, why does task.print_times() prints the elapsed time correctly...
2022-02-24 21:35:23
2022-02-24 21:35:26
0:00:03
But task.dict_times() prints this...
{
'time_start': '2022-02-24 21:35:23',
'time_end': '2022-02-24 21:35:26',
'time_elapsed': datetime.timedelta(seconds=3)
}
Code
from datetime import timedelta
from timeit import default_timer as timer
from time import strftime, localtime, sleep
class Timer:
'''A utility class for capturing a task's processing time.
'''
def __init__(self):
self.start_timer = None
self.time_start = None
self.stop_timer = None
self.time_stop = None
self.time_elapsed = None
def start(self):
'''Start the timer and capture the start time.
'''
self.start_timer = timer()
self.time_start = strftime("%Y-%m-%d %H:%M:%S", localtime())
def stop(self):
'''Stop the timer and capture the stop time.
'''
self.stop_timer = timer()
self.time_stop = strftime("%Y-%m-%d %H:%M:%S", localtime())
def elapsed(self):
'''Calculates the elapsed time.
'''
elapsed = timedelta(seconds=self.stop_timer-self.start_timer)
self.time_elapsed = elapsed - timedelta(microseconds=elapsed.microseconds)
# --------------------------
# Example usage
# --------------------------
class Task:
def __init__(self):
self.task_timer = Timer()
self.time_summary = {}
def do(self):
self.task_timer.start()
sleep(3)
self.task_timer.stop()
self.task_timer.elapsed()
def print_times(self):
print(self.task_timer.time_start)
print(self.task_timer.time_stop)
print(self.task_timer.time_elapsed)
def dict_times(self):
self.time_summary['time_start'] = self.task_timer.time_start
self.time_summary['time_end'] = self.task_timer.time_stop
self.time_summary['time_elapsed'] = self.task_timer.time_elapsed
print(self.time_summary)
task = Task()
task.do()
task.print_times()
task.dict_times()
When you print a dictionary, the individual keys/elements within are printed according to the value returned by their __repr__ methods. When you print an object directly, the __str__ method is invoked instead.
Consider this simple example:
class Foo:
def __str__(self):
return 'foo'
def __repr__(self):
return 'bar'
x = Foo()
d = {'a': x}
print(x) # -> foo
print(d) # -> {'a': bar}
This question gives a good explanation of the difference between str/__str__ and repr/__repr__.
Related
I tried to write a decorator to compute the time of the computation for methods in a class, but I also have a lot of properties.
I tried to write a decorator for a property as follows:
def timer(method):
import time
#property
def wrapper(*args, **kw):
start = time.time()
result = method
end = time.time()
print('Elapsed time for: {} is: {}s'.format(method.__name__,(end-start)*1000))
return result
return wrapper
I can't get the name of the property as written, moreover perhaps you would suggest to write it in another way?
You would need to stack decorators:
def timer(method):
import time
def wrapper(*args, **kwargs):
start = time.time()
result = method(*args, **kwargs) # note the function call!
end = time.time()
print('Elapsed time for: {} is: {}s'.format(method.__name__,(end-start)*1000))
return result
return wrapper
class X:
#property
#timer
def some_method(self):
# timed code
return 0
>>> x = X()
>>> x.some_method
Elapsed time for: some_method is: 0.0050067901611328125s
0
I am running a flask application which shall call a function getSomething(input) every day at the same time. This function returns a string. I can not return a print() because I need to pass the string to another function.
When using the Timer function
t = Timer(secs, getSomething, args=[input])
I do not know how to aces the return value of the getSomething function.
example:
from datetime import datetime, timedelta
from threading import Timer
# This shall trigger something at a certain time^
x = datetime.today()
y = x + timedelta(seconds=5)
delta_t = y - x
secs = delta_t.seconds + 1
def getSomething(a):
b = a + " Hello World"
return b
s = "Test"
t = Timer(secs, getSomething, args=[s])
t.start()
I know the very same question has been asked here before. But I am not able to adapt it to my problem though I think i can not avoid the return.
The problem can be solved the following way:
from datetime import datetime, timedelta
from threading import Timer
d = [] # use list, dictionary, some class or queue.Queue to store data
def getSomething(a):
global d
d.append(a + " Hello World")
if __name__ == "__main__":
# This shall trigger something at a certain time^
x = datetime.today()
y = x + timedelta(seconds=5)
delta_t = y - x
secs = delta_t.seconds + 1
s = "Test"
t = Timer(secs, getSomething, args=[s])
t.start()
t.join() # need to wait until thread is finished to get new d value
print(d[0])
Another exmple how you can get data from another thread:
from threading import Thread
import time
class Storage:
def __init__(self):
self.storage = ""
class MyThread(Thread):
def __init__(self, group=None, target=None, name=None, args=(), kwargs=None, *, daemon=None):
super().__init__(group=group, target=target, name=name, daemon=daemon)
self.args = args
self.kwargs = kwargs
def run(self):
self.args[0].storage += "Hello!"
if __name__ == "__main__":
s = Storage()
branch = MyThread(args=(s,),)
branch.start()
time.sleep(1) # need some time to wait for another thread
print(s.storage)
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.
Here is an example of using contextmanager
from time import perf_counter
from contextlib import contextmanager
#contextmanager
def catchtime() -> float:
start = perf_counter()
yield lambda: perf_counter() - start
with catchtime() as t:
import time
time.sleep(1)
print(f"Execution time: {t():.4f} secs")
Output:
Execution time: 1.0014 secs
The top-rated answer can give the incorrect time
As noted 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 run 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.
In some cases, this can be avoided by inserting 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
print(f'Time: {perf_counter() - start:.3f} seconds')
However, even with this modification, notice how running sleep(5) later on 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"
Solution #1: A fix for the above approach
This solution cumulatively nets the difference between two timer objects, t1 and t2. The catchtime function can be distilled down into 3 lines of code. Note that perf_counter has been renamed to press_button to help with visualization.
Initialize t1 and t2 simultaneously. Later t2 will be reassigned to preserve the tick count after the yield statement. For this step, imagine simultaneously pressing the on/off button for timer1 and timer2.
Measure the difference between timer2 and timer1. Initially, this will be 0 on pass #1, but in subsequent runs, it will be the absolute difference between the tick count in t1 and t2.
This final step is equivalent to pressing the on/off button for timer2 again. This puts the two timers out of sync, making the difference measurement in the step before meaningful from pass #2 onwards.
from time import perf_counter as press_button
from time import sleep
#contextmanager
def catchtime() -> float:
t1 = t2 = press_button()
yield lambda: t2 - t1
t2 = press_button()
with catchtime() as t:
sleep(1)
sleep(5)
print(f'Time: {t():.3f} seconds')
# >>> Time: 1.000 seconds
Solution #2: An alternative, more flexible approach
This code is similar to the excellent answer given by #BrenBarn, except that it:
Automatically prints the executed time as a formatted string (remove this by deleting the final print(self.readout))
Saves the formatted string for later use (self.readout)
Saves the 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 affect 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"
You can't get that to assign your timing to t. As described in the PEP, the variable you specify in the as clause (if any) gets assigned the result of calling __enter__, not __exit__. In other words, t is only assigned at the start of the with block, not at the end.
What you could do is change your __exit__ so that instead of returning the value, it does self.t = time.clock() - self.t. Then, after the with block finishes, the t attribute of the context manager will hold the elapsed time.
To make that work, you also want to return self instead of 1 from __enter__. Not sure what you were trying to achieve by using 1.
So it looks like this:
class catchtime(object):
def __enter__(self):
self.t = time.clock()
return self
def __exit__(self, type, value, traceback):
self.t = time.clock() - self.t
with catchtime() as t:
time.sleep(1)
print(t.t)
And a value pretty close to 1 is printed.
Solved (almost). Resulting variable is coercible and convertible to a float (but not a float itself).
class catchtime:
def __enter__(self):
self.t = time.clock()
return self
def __exit__(self, type, value, traceback):
self.e = time.clock()
def __float__(self):
return float(self.e - self.t)
def __coerce__(self, other):
return (float(self), other)
def __str__(self):
return str(float(self))
def __repr__(self):
return str(float(self))
with catchtime() as t:
pass
print t
print repr(t)
print float(t)
print 0+t
print 1*t
1.10000000001e-05
1.10000000001e-05
1.10000000001e-05
1.10000000001e-05
1.10000000001e-05
The issue in top rated answer could be also fixed as below:
#contextmanager
def catchtime() -> float:
start = perf_counter()
end = start
yield lambda: end - start
end = perf_counter()
I like this approach, which is simple to use and allows a contextual message:
from time import perf_counter
from contextlib import ContextDecorator
class cmtimer(ContextDecorator):
def __init__(self, msg):
self.msg = msg
def __enter__(self):
self.time = perf_counter()
return self
def __exit__(self, type, value, traceback):
elapsed = perf_counter() - self.time
print(f'{self.msg} took {elapsed:.3f} seconds')
Use it this way:
with cmtimer('Loading JSON'):
with open('data.json') as f:
results = json.load(f)
Output:
Loading JSON took 1.577 seconds
You could do it in this way below:
import time
class Exectime:
def __enter__(self):
self.time = time.time()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.time = time.time() - self.time
with Exectime() as ext:
<your code here in with statement>
print('execution time is:' +str(ext.time))
It will calculate time spent to process codes within 'with' statement.
With this implementtion you can get time during the process and any time after
from contextlib import contextmanager
from time import perf_counter
#contextmanager
def catchtime(task_name='It', verbose=True):
class timer:
def __init__(self):
self._t1 = None
self._t2 = None
def start(self):
self._t1 = perf_counter()
self._t2 = None
def stop(self):
self._t2 = perf_counter()
#property
def time(self):
return (self._t2 or perf_counter()) - self._t1
t = timer()
t.start()
try:
yield t
finally:
t.stop()
if verbose:
print(f'{task_name} took {t.time :.3f} seconds')
Usage examples:
from time import sleep
############################
# 1. will print result
with catchtime('First task'):
sleep(1)
############################
# 2. will print result (without task name) and save result to t object
with catchtime() as t:
sleep(1)
t.time # operation time is saved here
############################
# 3. will not print anyhting but will save result to t object
with catchtime() as t:
sleep(1)
t.time # operation time is saved here
I have a few classes that rely on time.perf_counter() to timestamp events and do things after a certain amount of time passes, like this:
class Alarm:
def setAlarm(self):
self.alarmed = False
self._saved = time.perf_counter()
def runStep(self):
now = time.perf_counter()
if now - self._saved > 1000.0 and self._saved != -1:
self.alarmed = True
self._saved = -1
I would like to test the class Alarm using a fake clock, it does not necessary to be a call to time.perf_counter() (though it would be more elegant if it does, I guess). I want that the fake clock does not increment by itself, but rather upon my command, like this:
alarm = Alarm()
alarm.setAlarm()
clock.increment(999.0)
alarm.runStep()
self.assertFalse(alarm.alarmed)
clock.increment(1.1) # tick another second
alarm.runStep()
self.assertTrue(alarm.alarmed)
Could you please advise on how to mock time.perf_counter() or mock my class for it, and what kind of tool should be used for this kind of job?
You can use unittest.mock.
For example:
import time
import unittest
import unittest.mock
class Alarm:
def setAlarm(self):
self.alarmed = False
self._saved = time.perf_counter()
def runStep(self):
now = time.perf_counter()
if now - self._saved > 1000.0 and self._saved != -1:
self.alarmed = True
self._saved = -1
class MockPerfCounter:
def __init__(self):
self.t = 0
def increment(self, n):
self.t += n
def perf_counter(self):
return self.t
class TestAlarm(unittest.TestCase):
def test_foo(self):
clock = MockPerfCounter()
with unittest.mock.patch('time.perf_counter', clock.perf_counter):
alarm = Alarm()
alarm.setAlarm()
clock.increment(999.0)
alarm.runStep()
self.assertFalse(alarm.alarmed)
clock.increment(1.1) # tick another second
alarm.runStep()
self.assertTrue(alarm.alarmed)
if __name__ == '__main__':
unittest.main()
Alterantively, instead of manual MockPerfCounter, you can also use unittest.mock.Mock:
class TestAlarm(unittest.TestCase):
def test_foo(self):
clock = unittest.mock.Mock()
clock.t = 0
with unittest.mock.patch('time.perf_counter', lambda: clock.t):
alarm = Alarm()
alarm.setAlarm()
clock.t += 999.0
alarm.runStep()
self.assertFalse(alarm.alarmed)
clock.t += 1.1
alarm.runStep()
self.assertTrue(alarm.alarmed)
I am trying to write a method that counts down to a given time and unless a restart command is given, it will execute the task. But I don't think Python threading.Timer class allows for timer to be cancelable.
import threading
def countdown(action):
def printText():
print 'hello!'
t = threading.Timer(5.0, printText)
if (action == 'reset'):
t.cancel()
t.start()
I know the above code is wrong somehow. Would appreciate some kind guidance over here.
You would call the cancel method after you start the timer:
import time
import threading
def hello():
print "hello, world"
time.sleep(2)
t = threading.Timer(3.0, hello)
t.start()
var = 'something'
if var == 'something':
t.cancel()
You might consider using a while-loop on a Thread, instead of using a Timer.
Here is an example appropriated from Nikolaus Gradwohl's answer to another question:
import threading
import time
class TimerClass(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.event = threading.Event()
self.count = 10
def run(self):
while self.count > 0 and not self.event.is_set():
print self.count
self.count -= 1
self.event.wait(1)
def stop(self):
self.event.set()
tmr = TimerClass()
tmr.start()
time.sleep(3)
tmr.stop()
I'm not sure if I understand correctly. Do you want to write something like in this example?
>>> import threading
>>> t = None
>>>
>>> def sayHello():
... global t
... print "Hello!"
... t = threading.Timer(0.5, sayHello)
... t.start()
...
>>> sayHello()
Hello!
Hello!
Hello!
Hello!
Hello!
>>> t.cancel()
>>>
The threading.Timer class does have a cancel method, and although it won't cancel the thread, it will stop the timer from actually firing. What actually happens is that the cancel method sets a threading.Event, and the thread actually executing the threading.Timer will check that event after it's done waiting and before it actually executes the callback.
That said, timers are usually implemented without using a separate thread for each one. The best way to do it depends on what your program is actually doing (while waiting for this timer), but anything with an event loop, like GUI and network frameworks, all have ways to request a timer that is hooked into the eventloop.
Im not sure if best option but for me is woking like this:
t = timer_mgr(.....) append to list "timers.append(t)" and then after all created you can call:
for tm in timers:#threading.enumerate():
print "********", tm.cancel()
my timer_mgr() class is this:
class timer_mgr():
def __init__(self, st, t, hFunction, id, name):
self.is_list = (type(st) is list)
self.st = st
self.t = t
self.id = id
self.hFunction = hFunction
self.thread = threading.Timer(t, self.handle_function, [id])
self.thread.name = name
def handle_function(self, id):
if self.is_list:
print "run_at_time:", datetime.now()
self.hFunction(id)
dt = schedule_fixed_times(datetime.now(), self.st)
print "next:", dt
self.t = (dt-datetime.now()).total_seconds()
else:
self.t = self.st
print "run_every", self.t, datetime.now()
self.hFunction(id)
self.thread = threading.Timer(self.t, self.handle_function, [id])
self.thread.start()
def start(self):
self.thread.start()
def cancel(self):
self.thread.cancel()
Inspired by above post.
Cancelable and Resetting Timer in Python. It uses thread.
Features: Start, Stop, Restart, callback function.
Input: Timeout, sleep_chunk values, and callback_function.
Can use or inherit this class in any other program. Can also pass arguments to the callback function.
Timer should respond in middle also. Not just after completion of full sleep time. So instead of using one full sleep, using small chunks of sleep and kept checking event object in loop.
import threading
import time
class TimerThread(threading.Thread):
def __init__(self, timeout=3, sleep_chunk=0.25, callback=None, *args):
threading.Thread.__init__(self)
self.timeout = timeout
self.sleep_chunk = sleep_chunk
if callback == None:
self.callback = None
else:
self.callback = callback
self.callback_args = args
self.terminate_event = threading.Event()
self.start_event = threading.Event()
self.reset_event = threading.Event()
self.count = self.timeout/self.sleep_chunk
def run(self):
while not self.terminate_event.is_set():
while self.count > 0 and self.start_event.is_set():
# print self.count
# time.sleep(self.sleep_chunk)
# if self.reset_event.is_set():
if self.reset_event.wait(self.sleep_chunk): # wait for a small chunk of timeout
self.reset_event.clear()
self.count = self.timeout/self.sleep_chunk # reset
self.count -= 1
if self.count <= 0:
self.start_event.clear()
#print 'timeout. calling function...'
self.callback(*self.callback_args)
self.count = self.timeout/self.sleep_chunk #reset
def start_timer(self):
self.start_event.set()
def stop_timer(self):
self.start_event.clear()
self.count = self.timeout / self.sleep_chunk # reset
def restart_timer(self):
# reset only if timer is running. otherwise start timer afresh
if self.start_event.is_set():
self.reset_event.set()
else:
self.start_event.set()
def terminate(self):
self.terminate_event.set()
#=================================================================
def my_callback_function():
print 'timeout, do this...'
timeout = 6 # sec
sleep_chunk = .25 # sec
tmr = TimerThread(timeout, sleep_chunk, my_callback_function)
tmr.start()
quit = '0'
while True:
quit = raw_input("Proceed or quit: ")
if quit == 'q':
tmr.terminate()
tmr.join()
break
tmr.start_timer()
if raw_input("Stop ? : ") == 's':
tmr.stop_timer()
if raw_input("Restart ? : ") == 'r':
tmr.restart_timer()