With-Syntax
The with syntax is very usefull especially in cases, where ressources are setup and are freed after their use, such as:
- Opening / Closing files
- Setting / releasing a lock or semaphore
- Ensuring a database commit and rolling back on an exception (see example 3 from here)
In order to implement them, there is already a ready to use AbstractContextManager class available, which just requires to implement a __enter__
and __exit__
method to implement e.g. a time keeper decorator:
from contextlib import AbstractContextManager
import time
class TrackTime(AbstractContextManager):
def __init__(self):
pass
def __enter__(self):
self.start_time = time.time()
def __exit__(self, *args):
end_time = time.time()
print(f"Total running time was: {end_time - self.start_time}")
with TrackTime():
time.sleep(2)
def tracktimefunction(func, *args, **kwargs):
def wrapping_function(*args, **kwargs):
start_time = time.time()
func(*args, **kwargs)
end_time = time.time()
print(f"Total running time was: {end_time - start_time}")
return
return wrapping_function
@tracktimefunction
def wait_2s():
time.sleep(2)
wait_2s()
The decorator can be easily integrated into the same class from above that served the purpose to time the time of a specific section of the code with the with syntax. This can be achieved by making the class "callable". The method __call__ will be responsible now for wrapping the function internally and it can be further simplified to use the with syntax with the class itself:
from contextlib import AbstractContextManager
import time
class TrackTime(AbstractContextManager):
def __init__(self):
pass
def __enter__(self):
self.start_time = time.time()
def __exit__(self, *args):
end_time = time.time()
print(f"Total running time was: {end_time - self.start_time}")
def __call__(self, func, *args, **kwargs):
def wrapping_function(*args, **kwargs):
with self:
return func(*args, **kwargs)
return wrapping_function
Now both, the decorator as well as the with syntax is possible within the same class:
@TrackTime()
def wait_2s():
time.sleep(2)
wait_2s()
with TrackTime():
time.sleep(3)