catalogue
Function closures that retain function parameters and return values:
3, Execution sequence of multiple decorators:
4, To create a decorator with parameters:
1, The essence of decorator:
The essence of decorator is the syntax sugar of function closure
function closure:
Function closure is a term in functional language (function is a first-class citizen and can be used as a variable). Function closure: a function whose parameters and return values are functions. It is used to enhance function functions and face aspect programming (AOP)
import time # The console prints odd numbers within 100: def print_odd(): for i in range(100): if i % 2 == 1: print(i) # Function closure: used to enhance function func: function of adding statistical time to function func: def count_time_wrapper(func): def improved_func(): start_time = time.time() func() end_time = time.time() print(f"It takes {end_time - start_time} S to find all the odds in range !!!") return improved_func if __name__ == '__main__': # Call count_time_wrapper enhancement function print_odd = count_time_wrapper(print_odd) print_odd()
A closure is essentially a function. The incoming parameters and return values of the closure function are functions. The return value function obtained by the closure function is the result of the enhancement of the incoming function.
Log decorator:
def log_wrapper(func): """ closure,For enhancement function func: to func Add log function """ def improved_func(): start_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) # Start time func() # Execution function end_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) # End time print("Logging: func:{} runs from {} to {}".format(func.__name__, start_time, end_time)) return improved_func
2, Use method of decorator:
Function enhancement through decorators is just a syntax sugar, which is essentially consistent with the previous program (using function closures).
import time # Function closure: used to enhance function func: function of adding statistical time to function func: def count_time_wrapper(func): def improved_func(): start_time = time.time() func() end_time = time.time() print(f"It takes {end_time - start_time} S to find all the odds in range !!!") return improved_func # The console prints odd numbers within 100: @count_time_wrapper # Add decorator def print_odd(): for i in range(100): if i % 2 == 1: print(i) if __name__ == '__main__': # Using @ decorator (enhanced function name) to add decorator to the current function is equivalent to executing the following statement: # print_odd = count_time_wrapper(print_odd) print_odd()
When the decorator calls the decorated function for the first time, it will be enhanced only once. The next call is still to call the enhanced function, and the enhancement will not be repeated!
Function closures that retain function parameters and return values:
- The previously written function closure does not retain the parameter list and return value of the original main function function when enhancing the main function function.
- Write a function closure that retains the parameter list and return value:
def general_wrapper(func): def improved_func(*args, **kwargs): # Enhanced functions: ret = func(*args, **kwargs) # Enhanced functions: return ret return improved_func
Optimize decorator (parameter transfer, setting return value):
import time # Function closure: used to enhance function func: function of adding statistical time to function func: def count_time_wrapper(func): # Enhancement function: def improved_func(*args, **kwargs): start_time = time.time() result = func(*args, **kwargs) end_time = time.time() print(f"It takes {end_time - start_time} S to find all the odds in range !!!") # Return value of original function return result return improved_func # Calculate the sum of 0-lim odd numbers: @count_time_wrapper def count_odds(lim): cnt = 0 for i in range(lim): if i % 2 == 1: cnt = cnt + i return cnt if __name__ == '__main__': result = count_odds(10000000) print(f"The calculation result is{result}!")
3, Execution sequence of multiple decorators:
# Decorator 1: def wrapper1(func1): print("set func1") # Output when wrapper1 decorates the function def improved_func1(*args, **kwargs): print("call func1") # Output when wrapper 1 decorated function is called func1(*args, **kwargs) return None return improved_func1 # Trimmer 2: def wrapper2(func2): print("set func2") # Output when wrapper2 decorates the function def improved_func2(*args, **kwargs): print("call func1") # Output when wrapper 2 decorated function is called func2(*args, **kwargs) return None return improved_func2 @wrapper1 @wrapper2 def original_func(): pass if __name__ == '__main__': original_func() print("------------") original_func()
The execution result obtained here is that the wrapper2 decorator executes first because: the program executes from top to bottom. When running to:
@wrapper1 @wrapper2 def original_func(): pass
This code is parsed as follows by using function closure:
original_func = wrapper1(wrapper2(original_func))
Therefore, first decorate wrapper2, then decorate the enhancement function decorated by wrapper2, and then decorate wrapper1 to return the final enhancement function.
4, To create a decorator with parameters:
Decorators allow parameters to be passed in. A decorator with parameters will have three-tier functions, as shown below:
import functools def log_with_param(text): def decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): print('call %s():' % func.__name__) print('args = {}'.format(*args)) print('log_param = {}'.format(text)) return func(*args, **kwargs) return wrapper return decorator @log_with_param("param!!!") def test_with_param(p): print(test_with_param.__name__) if __name__ == '__main__': test_with_param("test")
Remove its @ syntax and restore the form of function call:
# Pass in the parameters of the decorator and receive the returned decorator function decorator = log_with_param("param!!!") # Incoming test_with_param function wrapper = decorator(test_with_param) # Call decorator function wrapper("I'm a param")