In the previous articles on the Python decorator series, we have learnt decorators, how they work and to implement a simple function based decorator and a class based decorator and decorator that supports parameters. In this article, we will create reusable decorator utility to measure execution time of a function and instance method in a class.

## Measure execution time of a function

```
from functools import wraps
import time
def timeit(func):
@wraps(func)
def timeit_wrapper(*args, **kwargs):
start_time = time.perf_counter()
result = func(*args, **kwargs)
end_time = time.perf_counter()
total_time = end_time - start_time
print(f'Function {func.__name__}{args} {kwargs} Took {total_time:.4f} seconds')
return result
return timeit_wrapper
@timeit
def calculate_something(num):
"""
Simple function that returns sum of all numbers up to the square of num.
"""
total = sum((x for x in range(0, num**2)))
return total
if __name__ == '__main__':
calculate_something(10)
calculate_something(100)
calculate_something(1000)
calculate_something(5000)
calculate_something(10000)
```

### How it works

- We decorate the function with timeit decorator
- decorator makes note of start time
- then executes the function
- decorator marks end time
- calculates time difference and prints the time taken for the function

Output

```
Function calculate_something(10,) {} Took 0.0000 seconds
Function calculate_something(100,) {} Took 0.0008 seconds
Function calculate_something(1000,) {} Took 0.0760 seconds
Function calculate_something(5000,) {} Took 2.4503 seconds
Function calculate_something(10000,) {} Took 7.9202 seconds
```

## Measure execution time of a method inside a class

```
from functools import wraps
import time
def timeit(func):
@wraps(func)
def timeit_wrapper(*args, **kwargs):
start_time = time.perf_counter()
result = func(*args, **kwargs)
end_time = time.perf_counter()
total_time = end_time - start_time
# first item in the args, ie `args[0]` is `self`
print(f'Function {func.__name__}{args} {kwargs} Took {total_time:.4f} seconds')
return result
return timeit_wrapper
class Calculator:
@timeit
def calculate_something(self, num):
"""
an example function that returns sum of all numbers up to the square of num
"""
total = sum((x for x in range(0, num**2)))
return total
def __repr__(self):
return f'calc_object:{id(self)}'
if __name__ == '__main__':
calc = Calculator()
calc.calculate_something(10)
calc.calculate_something(100)
calc.calculate_something(1000)
calc.calculate_something(5000)
calc.calculate_something(10000)
```

### How it works

- we decorate a method inside a class with timeit
- timeit takes all arguments, note that args[0] is
`self`

so you can call any other method inside the class using self - decorator makes note of start time
- then executes the function
- decorator marks end time
- calculates time difference and prints the time taken for the function

Output

```
Function calculate_something(calc_object:140246512997904, 10) {} Took 0.0000 seconds
Function calculate_something(calc_object:140246512997904, 100) {} Took 0.0007 seconds
Function calculate_something(calc_object:140246512997904, 1000) {} Took 0.1820 seconds
Function calculate_something(calc_object:140246512997904, 5000) {} Took 1.9241 seconds
Function calculate_something(calc_object:140246512997904, 10000) {} Took 7.4005 seconds
```

In the next article, we will implement various kinds decorator recipes. Stay tuned for upcoming articles. Subscribe to the newsletter and Connect with me on twitter to get my future articles.

## Top comments (0)