Detailed explanation of decorators of python three major devices
- 2021-12-09 09:39:54
- OfStack
Decorator
There are two concepts to understand before talking about decorators:
Object reference: The object name is just a variable bound to the memory address
def func(): # The function name is just a variable bound to the memory address
print("i`m running")
# This is the call to the
func() # i`m running
# This is an object reference, which refers to the memory address
func2 = func
print(func2 is func) # True
# Called by reference
func2() # i`m running
Closure: Define a function A, and then define a function B inside the function, and the B function uses the variables of the outer A function
def out_func():
out_a = 10
def inner_func(inner_x):
return out_a + inner_x
return inner_func
out = out_func()
print(out) # <function out_func.<locals>.inner_func at 0x7ff378af5c10> out_func Returns the inner_func Memory address of
print(out(inner_x=2)) # 12
The difference between decorators and closures is that the parameters of decorators are function objects, while the parameters of closures are ordinary data objects
def decorator_get_function_name(func):
"""
Get the name of the running function
:return:
"""
def wrapper(*arg):
"""
wrapper
:param arg:
:return:
"""
print(f" Current running method name: {func.__name__} with params: {arg}")
return func(*arg)
return wrapper
@decorator_get_function_name
def test_func_add(x, y):
print(x + y)
@decorator_get_function_name
def test_func_sub(x, y):
print(x - y)
test_func_add(1, 2)
# Current running method name: test_func_add with params: (1, 2)
# 3
test_func_sub(3, 5)
# Current running method name: test_func_sub with params: (3, 5)
# -2
Commonly used such as authentication verification, for example, the author will be used for login verification:
def login_check(func):
def wrapper(request, *args, **kwargs):
if not request.session.get('login_status'):
return HttpResponseRedirect('/api/login/')
return func(request, *args, **kwargs)
return wrapper
@login_check
def edit_config():
pass
Execution logic inside the decorator:
"""
> 1. def login_check(func): ==> Will login_check Function loaded into memory
> ....
> @login_check ==> This is already in memory login_check This function is executed! ; You don't have to wait edit_config() Instantiation call
> 2. Above example @login_check The following actions are performed internally:
> 2.1 Execute login_check Function and set the @login_check Below Function (edit_config) As login_check Function, namely: @login_check Equivalent to login_check(edit_config)
> 2.2 It will be executed internally:
def wrapper(*args):
# Calibration session...
return func(request, *args, **kwargs) # func Is a parameter, and at this time func Equal to edit_config In this case, it is equivalent to edit_config(request, *args, **kwargs)
return wrapper # Returned wrapper , wrapper Represents a function object, not a function instantiation object
2.3 In fact, it is the original edit_config Function is stuffed into another 1 Among the functions , Another 1 Among the functions, you can do 1 Some operations; Re-execute edit_config
2.4 That will be executed login_check Function return value ( That is wrapper Object ) Re-assign this return value to a new edit_config Namely:
2.5 New edit_config = def wrapper:
# Calibration session...
return Original edit_config(request, *args, **kwargs)
> 3. That is, new edit_config()=login_check(edit_config):wrapper(request, *args, **kwargs):return edit_config(request, *args, **kwargs) It's a bit round. Let's look at the steps and understand them carefully.
"""
Similarly, a function can be decorated with multiple decorators, and the execution order is from top to bottom
from functools import wraps
def w1(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(" This is the first 1 Checkout ")
return func(*args, **kwargs)
return wrapper
def w2(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(" This is the first 2 Checkout ")
return func(*args, **kwargs)
return wrapper
def w3(func):
def wrapper(*args, **kwargs):
print(" This is the first 3 Checkout ")
return func(*args, **kwargs)
return wrapper
@w2 # This is actually w2(w1(f1))
@w1 # This is w1(f1)
def f1():
print(f"i`m f1, at {f1}")
@w3
def f2():
print(f"i`m f2, at {f2}")
# ====================== Instantiation phase =====================
f1()
# This is the first 2 Checkout
# This is the first 1 Checkout
# i`m f1, at <function f1 at 0x7febc52f5e50>
f2()
# This is the first 3 Checkout
# i`m f2, at <function w3.<lo
Some students may wonder why the f1 object prints "
<
function f1 at 0x7febc52f5e50
>
", the f2 object prints"
<
function w3..wrapper at 0x7febc52f5f70
>
"(that is, as a result of step 2.5, the value assigned is wrapper object), which is related to the wraps decorator used by wrapper inside w1 and w2.
The function of wraps is to assign one attribute value of the modified function (that is, func inside) to the modifier function (wrapper), including meta-information and "function object", etc.
At the same time, the decorator can also accept parameters:
def decorator_get_function_duration(enable):
"""
:param enable: Do you need to count the time spent on function execution
:return:
"""
print("this is decorator_get_function_duration")
def inner(func):
print('this is inner in decorator_get_function_duration')
@wraps(func)
def wrapper(*args, **kwargs):
print('this is a wrapper in decorator_get_function_duration.inner')
if enable:
start = time.time()
print(f" Before the function executes: {start}")
result = func(*args, **kwargs)
print('[%s]`s enable was %s it`s duration : %.3f s ' % (func.__name__, enable, time.time() - start))
else:
result = func(*args, **kwargs)
return result
return wrapper
return inner
def decorator_1(func):
print('this is decorator_1')
@wraps(func)
def wrapper(*args, **kwargs):
print('this is a wrapper in decorator_1')
return func(*args, **kwargs)
return wrapper
def decorator_2(func):
print('this is decorator_2')
@wraps(func)
def wrapper(*args, **kwargs):
print('this is a wrapper in decorator_2')
return func(*args, **kwargs)
return wrapper
@decorator_1 # It is quite here :decorator_1(decorator_2(decorator_get_function_duration(enable=True)(fun)))
@decorator_2 # = decorator_2(decorator_get_function_duration(enable=True)(fun))
@decorator_get_function_duration(enable=True) # = decorator_get_function_duration(enable=True)(fun)
def fun():
time.sleep(2)
print("fun Finished execution ~ ")
fun()
# ======== enable=False ============
"""
this is decorator_get_function_duration
this is inner in decorator_get_function_duration
this is decorator_2
this is decorator_1
this is a wrapper in decorator_1
this is a wrapper in decorator_2
this is a wrapper in decorator_get_function_duration.inner
fun Finished execution ~
"""
# ======== enable=True ============
"""
this is decorator_get_function_duration
this is inner in decorator_get_function_duration
this is decorator_2
this is decorator_1
this is a wrapper in decorator_1
this is a wrapper in decorator_2
this is a wrapper in decorator_get_function_duration.inner
Before the function executes: 1634635708.648994
fun Finished execution ~
[fun]`s enable was True it`s duration : 2.002 s
"""
Summarize
This article is here, I hope to give you help, but also hope that you can pay more attention to this site more content!