SoFunction
Updated on 2024-11-14

python basics of decorator details

I. Preface

Decorator: the essence is the function, the function is to add additional functionality to other functions

Principles:

  • 1, do not modify the source code of the modified function
  • 2. Do not modify the way the modified function is called

Decorators = higher-order functions + function nesting + closures

II. Higher-order functions

Higher-order function definitions:

  • 1, the function receives the parameters of a function
  • 2. The return value of a function is a function name
  • 3. Satisfying any of the above conditions can be called a higher order function

The test function is a higher-order function that takes a foo as an argument

import time
def foo():
    (3)
    print("sleep 3s")
 
def test(func):
    start_time = ()
    func()
    stop_time = ()
    print("The runtime of the function is: %s" % (stop_time - start_time))
 
test(foo)

timer is a higher-order function that returns a value of the function

import time
def foo():
    (3)
    print("sleep 3s")
 
def timer(func):
    start_time = ()
    func()
    stop_time = ()
    print("execution time{}".format(stop_time - start_time))
    return func
foo = timer(foo)
foo()
# Result: one more run

Third, function nesting

Defining a function inside a function leaves the scope and lifetime of the variable unchanged.

def father(name):
    print("father name: %s" % name)
    def son():
        print("son name: %s" % name)
    son()
father("xu1")
 
# Results:
#     father name: xu1
#     son name: xu1

IV. Decorators

Implement a function that calculates the execution time of a function as a decorator, which is used to calculate the execution time of the decorated function and print it

import time
 
def timer(func):  # Implement a function that calculates the execution time of a function as a decorator to calculate the execution time of the decorated function and hit the
    def wrapper():
        start_time = ()
        func()
        stop_time = ()
        print("Runtime: %s" % (stop_time - start_time))
    return wrapper
 
# def test(): # Equivalent implementation without decorator
#     (3)
#     print("test sleep 3s")
#
# test = timer(test) # returns the address of the wrapper
# test() # The execution is wrapper
 
 
@timer
def test():  # Decorator implementation
    (3)
    print("test sleep 3s")
 
test()  # The execution is wrapper
# Results:
#     test sleep 3s
# Running time: 3.000915050506592

4.1 Decorated methods with return values

import time
 
 
def timer(func):
    def wrapper():
        start_time = ()
        res = func()  # Execute the decorated method
        stop_time = ()
        print("Runtime: %s" % (stop_time - start_time))
        return res  # Accepts the return value of the method being called and returns the
    return wrapper
 
 
@timer
def test():
    (3)
    print("test sleep 3s")
    return "test return ok"
 
 
print(test())  # The execution is wrapper
# Results:
#     test sleep 3s
# Running time: 3.0002923011779785
#     test return ok

4.2 Decorated methods with parameters

import time
 
 
def timer(func):
    """
        *args: packs non-keyword arguments passed by the modified method into a tuple args
        **kwargs: packs keyword arguments passed by the modified method into a dictionary kwargs
    """
    def wrapper(*args, **kwargs):
        start_time = ()
        res = func(*args, **kwargs)  # *args disassembles tuples and passes them to the modified function in order; **kwargs: disassembles dictionaries
        stop_time = ()
        print("Runtime: %s" % (stop_time - start_time))
        return res
    return wrapper
 
 
@timer  # Add a decorator to the test method that calculates the execution time.
def test(name, age):
    (3)
    print("name = {}, age = {}".format(name, age))
    return "test return ok"
 
 
# Call the method decorated by the decorator
print(test("xu", 100))  # The execution is wrapper
# Results:
#     name = xu, age = 100
# Running time: 3.000420331954956
#     test return ok

4.3 Validation Function Decorator

If the index(), home(), and shopping_car() methods all need to be logged in to access them (without inputting the corresponding contents when they are inaccessible), then under normal circumstances you only need to log in once, and then you don't need to log in again to access the other methods later on.

You can verify whether the user is logged in through the @auth_fun decorator, if not let the user enter the account password, the user account password is correct to record the current logged in user, other methods do not need to log in again.

# User list
user_list = [
    {'name': 'xu1', 'passwd': '123'},
    {'name': 'xu2', 'passwd': '123'},
    {'name': 'xu3', 'passwd': '123'},
    {'name': 'xu4', 'passwd': '123'},
]
# Currently logged in user
current_dic = {"username": None, "login": False}
 
 
# Decorator to verify that the user is logged in
# If the user is not logged in, let the user enter the account password and record the user's status if the verification passes.
def auth_fun(func):
    def wrapper(*args, **kwargs):
        if current_dic["username"] and current_dic['login']:
            res = func(*args, **kwargs)
            return res
        username = input("Please enter username:")
        pw = input("Please enter the password:")
        for u in user_list:
            if u["name"] == username and u["passwd"] == pw:
                current_dic["username"] = username
                current_dic["login"] = True
                res = func(*args, **kwargs)
                return res
        else:
            print("The user is not registered!")
    return wrapper
 
 
@auth_fun
def index():
    print("this is index")
 
 
@auth_fun
def home():
    print("this is home page")
 
 
@auth_fun
def shopping_car():
    print("this is shopping car")
 
 
index()  # Enter user password
home()  # index is already logged in, there is no need to enter
shopping_car()  # index is already logged in, there is no need to enter
# Results:
# Please enter username:xu1
# Please enter password:123
#     this is index
#     this is home page
#     this is shopping car

4.4 Validation Function Decorator - with Parameters

The simplest operation of a decorator with parameters is the ability to differentiate between the functions being decorated.

# User list
user_list = [
    {'name': 'xu1', 'passwd': '123'},
    {'name': 'xu2', 'passwd': '123'},
    {'name': 'xu3', 'passwd': '123'},
    {'name': 'xu4', 'passwd': '123'},
]
# Currently logged in user
current_dic = {"username": None, "login": False}
 
"""
    take note of:Decorators with parameters will nest one more layer of functions than decorators without parameters(More.auth)
        The call is made by @auth(auth_type="type1"), come (or go) back auth_fun,
        in other words @auth(auth_type="type1")equivalent to @auth_fun
        still auth_fun 函数所在的嵌套作用域More.一个 auth_type variable
"""
def auth(auth_type="type1"):
    def auth_fun(func):
        def wrapper(*args, **kwargs):
            if auth_type == "type1":
                if current_dic["username"] and current_dic['login']:
                    res = func(*args, **kwargs)
                    return res
                username = input("Please enter username:")
                pw = input("Please enter the password:")
                for u in user_list:
                    if u["name"] == username and u["passwd"] == pw:
                        current_dic["username"] = username
                        current_dic["login"] = True
                        res = func(*args, **kwargs)
                        return res
                else:
                    print("The user is not registered!")
            elif auth_type == "type2":
                print("Direct login without authorization: type = {}".format(auth_type))
                res = func(*args, **kwargs)
                return res
            else:
                print("Other types are not realized.")
        return wrapper
    return auth_fun
 
 
"""
    auth_fun = @auth(auth_type="type1") 
    auth_fun The nesting where it is located is the same as the nesting where there will be a auth_type variant
    and then through @auth()methodologiescome (or go) back的boyfriendannotate index,equivalent to @auth_fun annotateindex methodologies,end result wrapper boyfriend
"""
@auth(auth_type="type1")
def index():
    print("this is index")
 
 
@auth(auth_type="type2")
def home():
    print("this is home page")
 
 
@auth(auth_type="type3")
def shopping_car():
    print("this is shopping car")
 
 
home()  # Note: auth_type="type2", this method can be executed directly without login.
index()  # Note: auth_type="type1", requires login
shopping_car()  # Note: auth_type="type3", not processed
# Results:
# Login without authorization: type = type2
#     this is home page
# Please enter username:xu1
# Please enter password:123
#     this is index
# Other types not implemented

to this article on the basis of python decorator detailed article is introduced to this, more related python decorator content please search for my previous articles or continue to browse the following related articles I hope you will support me in the future more!