Detailed Explanation of python Basic Decorator
- 2021-10-27 08:25:13
- OfStack
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 calledDecorator = 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 functionThe 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