# Decorators allow you to make simple modifications to callable objects like functions, methods, or classes. We shall deal with functions for this tutorial. The syntax # @decorator # def functions(arg): # return "value" # #Is equivalent to: # def function(arg): # return "value" # function = decorator(function) # this passes the function to the decorator, and reassigns it to the functions # function(5) def repeater(old_function): def new_function(*args, **kwds): # See learnpython.org/en/Multiple%20Function%20Arguments for how *args and **kwds works old_function(*args, **kwds) # we run the old function old_function(*args, **kwds) # we do it twice return new_function # we have to return the new_function, or it wouldn't reassign it to the value @repeater def multiply(num1, num2): print(num1 * num2) multiply(2, 3) def multiply(multiplier): def multiply_generator(old_function): def new_function(*args, **kwds): return multiplier * old_function(*args, **kwds) return new_function return multiply_generator # it returns the new generator # Usage @multiply(3) # multiply is not a generator, but multiply(3) is def return_num(num): return num # Now return_num is decorated and reassigned into itself return_num(5) # should return 15