Detailed Explanation of python Basic Decorator

  • 2021-10-27 08:25:13
  • OfStack

Directory 1. Preface 2. High-order functions 3. Function nesting 4. Decorator 4.1 Decorated method with return value 4.2 Decorated method with parameter 4.3 Verification function decorator 4.4 Verification function decorator-with parameter

1. Preface

Decorator: It is essentially a function, and the function is to add additional functions to other functions

Principles:

1. Do not modify the source code of the decorated function 2. Do not modify how the decorated function is called

Decorator = higher order function + function nesting + closure

2. Higher order functions

Definition of higher order function:

1. The parameter received by the function is a function 2. The return value of the function is 1 function name 3. If any one of the above conditions is satisfied, it can be called a high-order function

The test function is a higher order function and takes one foo as a parameter


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

timer is a higher order function, and the return value of this function is a function


import time
def foo():
    time.sleep(3)
    print("sleep 3s")
 
def timer(func):
    start_time = time.time()
    func()
    stop_time = time.time()
    print(" Execution time {}".format(stop_time - start_time))
    return func
foo = timer(foo)
foo()
#  Results:   Run more 1 Times 

3. Function nesting

The function is defined in the function, and the scope and life cycle of variables are 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

STEP 4 Decorator

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


import time
 
def timer(func):  #  Realization 1 A function that calculates the execution time of a function is used as a decorator to calculate the execution time of the decorated function and type it 
    def wrapper():
        start_time = time.time()
        func()
        stop_time = time.time()
        print(" Running time:  %s" % (stop_time - start_time))
    return wrapper
 
# def test():  #  Equivalent implementation without decorator 
#     time.sleep(3)
#     print("test sleep 3s")
#
# test = timer(test)  #  Returns the  wrapper  The address of 
# test()  #  Executed is  wrapper
 
 
@timer
def test():  #  Realization of decorator 
    time.sleep(3)
    print("test sleep 3s")
 
test()  #  Executed is  wrapper
#  Results: 
#     test sleep 3s
#      Running time:  3.000915050506592

4.1 Decorated method with return value


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

4.2 Decorated method with parameters


import time
 
 
def timer(func):
    """
        *args Package non-keyword parameters passed in by decorated methods as tuples  args
        **kwargs:  Package keyword parameters passed in by decorated methods as dictionaries  kwargs
    """
    def wrapper(*args, **kwargs):
        start_time = time.time()
        res = func(*args, **kwargs)  # *args  Disassemble tuples and pass them to modified functions in sequence;  **kwargs : Disassemble the dictionary 
        stop_time = time.time()
        print(" Running time:  %s" % (stop_time - start_time))
        return res
    return wrapper
 
 
@timer  #  To test  Method to add a decorator to calculate the execution time 
def test(name, age):
    time.sleep(3)
    print("name = {}, age = {}".format(name, age))
    return "test return ok"
 
 
#  Call the method decorated by the decorator 
print(test("xu", 100))  #  Executed is  wrapper
#  Results: 
#     name = xu, age = 100
#      Running time:  3.000420331954956
#     test return ok

4.3 Verify the function decorator

If index (), home (), shopping_car () three methods need to be logged in before they can be accessed (when they can't be accessed, they don't input corresponding contents). Under normal circumstances, they only need to log in once, and they don't need to log in again when accessing other methods later.

You can verify whether the user logs in through @ auth_fun decorator. If not, let the user enter the account password, and the user account password correctly records the currently 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'},
]
#  User currently logged in 
current_dic = {"username": None, "login": False}
 
 
#  Decorator to verify whether the user is logged in 
#    If the user is not logged in, let the user enter the account password, and record the user status through verification 
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 a user name :")
        pw = input(" Please enter your 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(" 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 the user password 
home()  # index  You are already logged in, so you don't need to enter 
shopping_car()  # index  You are already logged in, so you don't need to enter 
#  Results: 
#      Please enter a user name :xu1
#      Please enter your password :123
#     this is index
#     this is home page
#     this is shopping car

4.4 Verify Function Decorator-With Parameters

The decorator has parameters, and the simplest operation is to distinguish the decorated functions.


#  User list 
user_list = [
    {'name': 'xu1', 'passwd': '123'},
    {'name': 'xu2', 'passwd': '123'},
    {'name': 'xu3', 'passwd': '123'},
    {'name': 'xu4', 'passwd': '123'},
]
#  User currently logged in 
current_dic = {"username": None, "login": False}
 
"""
     Note: Decorators with parameters are more nested than decorators without parameters 1 Layer function (too many auth ) 
         The calling mode is  @auth(auth_type="type1") ,   Return  auth_fun , 
         That is to say  @auth(auth_type="type1") Equivalent to  @auth_fun
         But  auth_fun  Functions have more nested scopes 1 A  auth_type  Variables of 
"""
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 a user name :")
                pw = input(" Please enter your 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(" User is not registered! ")
            elif auth_type == "type2":
                print(" Log in directly without authorization : type = {}".format(auth_type))
                res = func(*args, **kwargs)
                return res
            else:
                print(" Others type Not implemented ")
        return wrapper
    return auth_fun
 
 
"""
    auth_fun = @auth(auth_type="type1") 
    auth_fun  Is nested and will have 1 A  auth_type  Variable 
     And then through  @auth() Object annotation returned by method  index, Equivalent to  @auth_fun  Annotation index  Method, and finally get the  wrapper  Object 
"""
@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 logging in 
index()  #  Note: auth_type="type1" You need to log in 
shopping_car()  #  Note: auth_type="type3" , did not do the processing 
#  Results: 
#      Log in directly without authorization : type = type2
#     this is home page
#      Please enter a user name :xu1
#      Please enter your password :123
#     this is index
#      Others type Not implemented 

Related articles: