Write the interface case when , Sometimes you need to be right about cae Do some common operations , The most typical scenes are : obtain case execution time 、 Print log etc. .
Is there a way to focus on common operations so as to avoid them in every case Write the same code in ( Such as : Every case All need to write the same code to get the execution time ) Well ?
Python The decorator can do this .
The decorator can be understood in this way , The decorator decorates the objective function with closures ( The reference of the objective function as the external function of the closure ), That is, before executing the objective function 、 Then execute some specified code to complete the desired business logic .
Concepts always seem obscure , Go straight to grammar .
First step , Let's first look at the syntax of closures :
def outer(a): b = 10
# inner It's an internal function
def inner(): # In the inner function We use the temporary variable of the external function
print(a + b) # The return value of the outer function is a reference to the inner function
return inner
The second step , Let's look at the syntax of the decorator version of closures :
There is only one difference between... And the above example : The outer part of the reference function is an integer a, This is a function reference ( The reference of the function is Function name ).
# The decorator uses the closure principle : An inner function is defined inside the outer function , The inner function uses the local variables of the outer function , And the outer function returns the reference of the inner function
def outer(target): # Decorator function Pass in an object function that you want to decorate quote , Use... In the inner function .
b = 10 c = 1 d = 5
# inner It's an internal function
def inner(): print(b + c) # Parameters passed in by external functions target, Is the reference of the objective function you want to decorate
target() # The objective function is actually executed here , Want to decorate this function , So do something before and after the function is executed , The specific operation depends on the business logic
print(c + d) # The return value of the outer function is a reference to the inner function
return inner
Be careful :target Just a reference to a function ( The reference points to the location of the function in memory ), Not execute . belt () when ( target() ) Will execute the function .
The last step , Take another look at the grammar of the decorator :
@decorator def test_01():
So it can be concluded that : Decorator decorator Is an external function of a closure , namely outer() ( Decorator It's a function , namely External functions of closures ), Decorated function test_01 Is the parameter passed in by the closure , namely target.
for instance :
Take the time-consuming statistics of each interface request as an example .
Decorator (decorat.py):
import time def time_consume(func): def inner(): time_start = time.time() # Take the time before the objective function starts
print("\n The time before the interface request is ", time_start) func() time_end = time.time() # Take the time after the end of the objective function
print(" The time after the interface request is ", time_end) t = time_end - time_start # Calculate how long the objective function takes to execute
print(" The interface takes :", t) return inner
Interface (test_case.py):
import requests import decorat @decorat.time_consume def test_demo(): res = requests.get("https://www.baidu.com") assert res.status_code == 200
effect :
Let's summarize the whole process of this example :
''' @decorat.time_consume It's actually executing : test_demo = @decorat.time_consume(test_demo) Because programming languages are parsed and executed from right to left , So what happens to this code is : 1 、 Put the objective function test_demo( It's a variable name , There is a reference to the objective function ) Pass in time_consume function , By parameter func receive , At this time func It is also a reference to the objective function func and test_demo Point to the same function object 2 、time_consume Function defines the inner function inner, stay inner Call inside func, This uses the principle of closure ( Closure principle : When the outer function ends, it will bind its own reference to the inner function ), When the outer function ends, it will put func Bound to inner functions , For inner functions 3、 At the end of the outer function, reference the inner function you created inner Return to test_demo receive , At this time test_demo It is not the original objective function ,test_demo It can be understood as a inner The instance object of the function , Re execution test_demo() In fact, it was executed inner() An object of 4、 Re execution test_demo() When Actually inner() : Execute fetch time first , Print After performing func(), Is to execute the objective function , The perform test_demo() In itself Finally, take the time again , Print the results '''
Great vernacular version :
In fact, just a word :
The decorated function is passed in as a parameter of the decorator's external function , Execute the decorated function in the internal function of the decorator , Plus other code snippet A,
In addition to having its own logic , It also has the inner function of the decorator code snippet A The logic of . So that there is no need to modify the decorated function ,
This enhances the function of the decorated function .
Let's look at two scenarios .
first : The decorated function has parameters
General interface test test_case I don't want to mention a function in the above example , But as a method of a class , such as :
The operation report is wrong , The error log means inner() need 0 Input parameters , But it was introduced 1 individual . The error report proves the conclusion mentioned above
as a result of test_demo() With parameters self, and inner() No input parameters defined . How to solve it , to inner() Define a variable input parameter ? Let's start with the second question , Finally, let's prove our conjecture .
the second : The decorated function has a return value
The problem arises , The return value printed out is None, because inner() There are no variables to receive test_demo Return value of and return ? Speculation with the first question , Let's change the code .
do 2 There are two changes :
1、inner() Define variable input parameters
2、inner() To define variables test_demo Return value of and return The variable
test_case As a class method, the problem is solved .
The printed value can also be returned as normal .
The modified decorator can be used as a general template to define the decorator , Basically, it can be decorated with various functions .
def decorat_demo(func): def inner(*args, **kwargs): # inner() Receive variable parameters
# any code before # Operations before defining the objective function
# Call target function
res = func(*args, **kwargs) # Define the variable to receive the return value of the objective function
# any code after # Operation after defining the objective function
return res # Return the return value of the objective function
return inner