SIMPLE DECORATOR SYNTAX

1- Define a decorator

def decorator_function(function):
    def wrapper_function():
        # Do something before the function
        function()
        # Do something after the function
    return wrapper_function

Python Decorator Function (4 lines of code)

1- Create a normal function.
2- Input is another normal function, the function in this case doesn't have parentheses ().
3- Inside the decorator_function, create a wrapper_function
The wrapper_function() will trigger the actual input "function()" that was passed into the decorator_function().
4- Return the wrapper_function without parentheses ().

Key takeaways:
+ Decorator function is just a function that wraps another function,
  + And GIVE that function some ADDITIONAL FUNCTIONALITY

2.1 - Using a decorator function by @ sign -> RECOMMENDED way.

@decorator_function #this line will trigger the decorator function for a_normal_function
def a_normal_function():
    pass

2.2 - Using a decorator function by input function -> NOT RECOMMENDED way.

decorated_func = decorator_function(a_normal_function)
decorated_func() # remember to add parentheses ()

EXAMPLES

Requirements:

  • All functions should be delayed by 5 seconds.
  • Avoid adding time.sleep(5) to each function.
  • Add time.sleep(5) once.

Implementation:

We can modify delay_decorator to delay the execution of the wrapped function by 5 seconds.

import time

def delay_decorator(function):
    def wrapper_function():
        time.sleep(5) # wait 5 seconds before executing the next function
        function()
    return wrapper_function


@delay_decorator
def say_hello():
    print("Hello!")

@delay_decorator
def say_bye():
    print("GoodBye!")

def say_greeting():
    print("How are you?")

Now we will define a main_flow:

def main_flow():
    say_hello() # no delay because we don't add @delay_decorator to it
    say_greeting() # delay 5s before executing greeting
    say_bye() # delay 5s before executing GoodBye

main_flow()

Result:

Hello!
wait 5s
How are you?
wait 5s
GoodBye!

ADVANCE DECORATOR SYNTAX

Class and Adv Python Decorator

1. Requirements:

Users have to provide their name, and is_logged_in = True
Create a decorator to ensure users log in by using the "is_authenticated_decorator()"

2. Define a class name User:

class User:
    def __init__(self, name):
        self.name = name
        self.is_logged_in = False

2. The function to create a new blog post:

def create_blog_post(user):
    print(f"This is {user.name}'s new blog post.")

3. Define a decorator:

To check whether users log in or not
Remember the create_blog_post function requires a param name user.
With Decorator, we cannot send param directly, in this case, we can use *args and **kwars.
args[0] means the first argument input.

def is_authenticated_decorator(function):
    def wrapper(*args, **kwargs):
        user = args[0]
        if user.is_logged_in:
            function(user)
        else:
            print("Please log in!")
    return wrapper

4. Main Flow:

# If is_logged_in = True, a new blog post will be created.
new_user = User("Anvo0000")
new_user.is_logged_in = True
create_blog_post(new_user)
# --> This is Anvo0000's new blog post.

# If no log-in:
new_user.is_logged_in = False
create_blog_post(new_user)
# --> Please log in!

P/S: if the function has a return value, remember to return that result in a wrapper.

def logging_decorator(function):
    def wrapper(*args):
        result = function(*args)
        print(f"You called {function.__name__}{args}")
        print(f"It returned: {result}")
        return result # IMPORTANT: remember to return a result for the follower function.
    return wrapper

@logging_decorator
def sum_function(*args):
    return sum(args)

sum_function(1,2,3)