I recommend that you look into what are called python decorators
.
Consider the following code:
import functools
def decorator(f):
@functools.wraps(f)
def wrapped_f(*args, **kwargs):
print('start of function')
r = f(*args, **kwargs)
print('end of function')
return r
return wrapped_f
@decorator
def print_strawberries():
print("strawberries")
print_strawberries()
Even if you don't quite understand the code, know that the text printed to the console is:
start of function
strawberries
end of function
In some way, we have changed print_strawberries
. The new version also prints start of function
and end of function
.
The notation @decorator
is equivalent to the following:
def print_strawberries():
print("strawberries")
print_strawberries = decorator(print_strawberries)
Even better that function decorators are classes which define their own __call__
methods. __call__
is the paren-paren operator ()
. That is print("hello world")
is actually print.__call__("hello world")
class Decorator:
def __init__(self, callable):
self._callable = callable
def __call__(self, *args, **kwargs):
print('start of function')
r = self._callable(*args, **kwargs)
print('end of function')
return r
###################################################
@Decorator
def print_strawberries():
print("strawberries")
print_strawberries()
###################################################
def add_two(x, y):
return x + y
add_two = Decorator(add_two)
result = add_two(0, 1)
print(result)
###################################################