Finally figured out the Python decorator, let me talk about the decorator I understand

Table of contents

1. Overview of decorators

2. Introduction to decorators

1.What is closure

2.What is a decorator?

3. The difference between closures and decorators

4. Why use decorators? 

5. Applicable scenarios

 3. How to use decorators

1. Understand the usage of decorators through cases

2. Detailed explanation of Python decorator execution order

4. Decorator passing parameters 

5. Decorator return value 

 6. Universal Decorator

 7. Decorator with parameters


1. Overview of decorators

A decorator is a function that is used to add additional functionality to other functions, that is, a function that extends the functionality of the original function.


2. Introduction to decorators

1.What is closure

To master decorators, you must first understand closures. After mastering closures, it will be easy to learn decorators.

Closure is to define an internal function in the external function. The internal function refers to the variables in the external function, and the return value of the external function is the internal function. Closures are the bridge between the inside of a function and the outside of the function.

For example: For example, if we call a function x with a return value, function x returns a function y for us. This function y is called a closure .

# 闭包
def out(i):      # 一个外层函数
    def inner(j):    # 内层函数
        return i*j
    return inner

Closure definition conditions:

  • There must be an inline function
  • Inline functions must reference variables in external functions
  • The return value of an external function must be an embedded function

 Case: The function test_in is a closure

def test(number):

    print("--1--")

    def test_in(number2):
        print("--2--")
        print(number+number2)

    print("--3--")
    return test_in

ret = test(100)  #先执行第3行,输出"--1--";再执行第5行,函数名(test_in),不执行函数内部;然后执行第10行,输出"--3--";然后返回(test_in)函数给(test)函数,赋值给ret对象。
print("-"*30)    #输出”------------------------------“
ret(1)           #执行(test_in)函数,执行第6行,输出"--2--";执行第7行,输出"101"(number=100,number2=1)。
ret(100)         #执行(test_in)函数,执行第6行,输出"--2--";执行第7行,输出"200"(number=100,number2=100)。
ret(200)         #执行(test_in)函数,执行第6行,输出"--2--";执行第7行,输出"300"(number=100,number2=200)。

 Output result:

--1--
--3--
------------------------------
--2--
101
--2--
200
--2--
300

Run analysis: First call the external function test and pass in the default value number, and use ret to point to the reference inside the returned function. When ret is called later, calculations will be performed based on calling the external function.

2.What is a decorator?

Decorator means decoration and decoration, and does not change the function of the original program. For example, if my house is not soundproofed, I would add a layer of soundproofing panels to the wall instead of building a new house. In this way, the house is still the same, but a sound insulation panel (decorator) is added to realize the sound insulation function of the house.

The same is true in the program. There will be no changes to the original function, new functions will be added, and the interface when calling the function will not change.

Decorators can be implemented based on functions or classes, and their usage is basically fixed. Its basic steps are:

  1. Define decorating functions (classes)
  2. Define business functions
  3. Add @decorated function name/class name in the previous line of the business function

Case: (Requirement: Add new functions based on the original function)

def w1(func):
    """装饰器函数"""
    def inner():
        func()
        print("这是添加的新功能")
    return inner

@w1  # 等同于调用函数的时候上方加上:f1 = w1(f1)
def f1():
    """业务函数"""
    print("---f1---")

@w1 # 等同于调用函数的时候上方加上:f2 = w1(f2)
def f2():
    """业务器函数"""
    print("---f2---")

f1()
f2()

Output result:

---f1---
这是添加的新功能
---f2---
这是添加的新功能

3. The difference between closures and decorators

Closures pass  variables , while decorators pass  functions . There is no difference other than that. In other words, decorators are a type of closure, and they are just  closures that pass functions .

4. Why use decorators? 

Open and closed principle
Open: refers to being open to extended functions Closed
: refers to being closed to modifying the source code

Decorators add new functions to the decorated object without modifying the source code and calling method of the decorated object.

5. Applicable scenarios

Functions define some functionality before and after execution.


 3. How to use decorators

1. Understand the usage of decorators through cases

Case:

def w1(fn):
    """装饰器函数"""
    print("---正在装饰---")
    def inner():
        print("---正在验证---")
        fn()
    return inner

@w1 # 只要Python解释器执行到这个代码,就开始自动进行装饰,而不是等到调用的时候才装饰
def f1():
    """业务函数"""
    print("---2---")
    return "hello python"

Output result:

---正在装饰---

Run the analysis:

Decoration begins when the code is executed to @w1 . We did not call function f1 but output " ---Decorating--- ". What we called was the decorated result.


Case:

def w1(fn):
    """装饰器函数"""
    print("---正在装饰1---")
    def inner():
        print("---正在验证---")
        fn()
    return inner

def w2(fn):
    """装饰器函数"""
    print("---正在装饰2---")
    def inner():
        print("---正在验证---")
        fn()
    return inner

@w1
@w2
def f1():
    """业务函数"""
    print("---3---")

 Output result:

---正在装饰2---
---正在装饰1---

Run the analysis:

@w1 is at the top, and the following needs to be a function, but below is @w2 . You must wait for @w2 to finish decorating before decorating @w1 , so first output  ---Decorating 2--- , and then output  ---Decorating 1 ---

2. Detailed explanation of Python decorator execution order

2.1 Case execution

 Case:

def decorator_a(func):
    print ('Get in decorator_a')
    def inner_a(*args, **kwargs):
        print ('Get in inner_a')
        return func(*args, **kwargs)
    return inner_a

def decorator_b(func):
    print ('Get in decorator_b')
    def inner_b(*args, **kwargs):
        print ('Get in inner_b')
        return func(*args, **kwargs)
    return inner_b

@decorator_b
@decorator_a
def f(x):
    print ('Get in f')
    return x * 2

f(1)

Output result:

Get in decorator_a
Get in decorator_b
Get in inner_b
Get in inner_a
Get in f

 Run the analysis:

The above code first defines two functions:  The function implemented by these two functions is to receive a function as a parameter and then return another created function ;decotator_a, decotator_b

In this created function, call the received function (text is more confusing than code). The last defined function f   uses the one defined above as the decorating function.decotator_a, decotator_b

When we call the decorated function f with 1 as the parameter ,  what is the order (in order to indicate the order of function execution, printout is used to view the order of function execution)? decotator_a, decotator_b

If you judge without thinking based on the bottom-up principle, execute first  decorator_a and then execute  , then output will be output first  , and   then output  However, it is not. decorator_bGet in decotator_aGet in inner_aGet in decotator_bGet in inner_b 

 2.2 The difference between functions and function calls

Why execute first inner_b and then execute inner_a ? In order to completely understand the above problem, we must first distinguish between two concepts: functions and function calls.

In the above example, f  is called a function, and f(1) is called a function call. The latter is the result of evaluating the parameters passed in by the former. In Python, a function is also an object, so  function f refers to a function object, and its value is the function itself. f(1) is a call to the function, and its value is the result of the call. According to the definition here, f(1) ) has a value of 2. Similarly, taking the above decorator_afunction as an example, it returns a function object inner_a , which is defined internally. The function func inner_a  is called in and the result of the call to function  func  is returned as a value.

2.3 The decorator function is executed immediately after the decorated function is defined.

What exactly happens when a decorator decorates a function. Now simplify our example and assume it looks like this:

def decorator_a(func):
    print ('Get in decorator_a')
    def inner_a(*args, **kwargs):
        print ('Get in inner_a')
        return func(*args, **kwargs)
    return inner_a

@decorator_a
def f(x):
    print ('Get in f')
    return x * 2

 Interpretation:

@decorator_a  #等同于调用函数的时候上方加上:f=decorator_a(f)
def f(x):
    print ('Get in f')
    return x * 2

# 相当于

def f(x):
    print ('Get in f')
    return x * 2

f = decorator_a(f)

 Run the analysis:

When the interpreter executes this code,  decorator_a it has been called. It passes the function name f as a parameter to the formal parameter fun , and returns a function inner_a generated internally , so thereafter f refers to what is  decorater_a returned inside  inner_a. So when the function f is called in the future , it is actually equivalent to a call The parameters passed to the function f will be passed to the function . When the function is called  , the received parameters (function name f ) will be passed to the formal parameter func=f.  , the final return is the value of calling function f , so on the outside it looks like calling function f directly . inner_ainner_ainner_ainner_a

2.4 Case execution sequence analysis

When you clarify the above two concepts, you can clearly see what happened in the most original example.
When the interpreter executes the following code, the sums have actually been called in order from bottom to top and the corresponding   sums  will be output . At this time, the function f is already equivalent to the function in the function . But because function f has not been called, the function has not been called, and by analogy,  the functions inside  the function have not been called, so   the sum  will not be output. decorator_adecorator_bGet in decorator_aGet in decorator_bdecorator_binner_binner_b inner_binner_aGet in inner_aGet in inner_b

Case:

def decorator_a(func):
    print ('Get in decorator_a')
    def inner_a(*args, **kwargs):
        print ('Get in inner_a')
        return func(*args, **kwargs)
    return inner_a

def decorator_b(func):
    print ('Get in decorator_b')
    def inner_b(*args, **kwargs):
        print ('Get in inner_b')
        return func(*args, **kwargs)
    return inner_b

@decorator_b
@decorator_a
def f(x):
    print ('Get in f')
    return x * 2

f(1)

Output result: 

Get in decorator_a
Get in decorator_b
Get in inner_b
Get in inner_a
Get in f

Then on line 21, when we call function  f passing parameter 1, the function is called ,inner_b it will print first  Get in inner_b, and then  inner_b the function is called inside the function, inner_a,so it will print again  Get in inner_a, and then  inner_a the original function f is called inside the function , and use the result as the final return value. At this point you should know why the output is like that, and have a certain understanding of what actually happens in the decorator execution sequence.

2.5 Summary of case execution sequence

-The order in which multiple decorators are executed is to execute the decorators in order from bottom to top, and then execute the function itself.

-The statements between the outer function and the inner function of the decorator are not decorated on the target function, but are additional operations when loading the decorator. 

Lines 15~19 are the process of loading the decorator , which is equivalent to executing f=decorator_b(decorator_a(f)) :

  1. At this time, decorator_a(f) is executed first , and the result is Get in decorator_a , pointing the formal parameter func to function f , and returning the functioninner_a;
  2. Then execute function decorator_b(inner_a) , the result is output Get in decorator_b , point the formal parameter func to function inner_a , and return function inner_b ;
  3. Function f itself is equivalent to function inner_b .

Line 21 actually calls the loaded functionreplacing the function name f with the function name inner_b .

  1. At this time, the function inner_b is actually executed ;
  2. When the function func() is reached, the function inner_a is executed;
  3. When the function func() is run, the unmodified function f is executed .

4. Decorator passing parameters 

Case: Pass 2 parameters

def w1(fn):
    """装饰器函数"""
    print("---正在装饰---")
    def inner(a, b):  # 如果a, b没有定义,那么会导致19行代码调用失败
        print("---正在验证---")
        fn(a, b)  # 如果没有把a, b当实参进行传递,那么会导致调用13行的函数失败
    return inner

@w1
def f1(a, b):
    """业务函数"""
    print(a + b)

f1(10, 20)

Output result:

---正在装饰---
---正在验证---
30

Case: variable length parameters

def w1(fn):
    """装饰器函数"""
    print("---正在装饰---")
    def inner(*args, **kwargs):  # 如果a, b没有定义,那么会导致19行代码调用失败
        print("---正在验证---")
        fn(*args, **kwargs)  # 如果没有把a, b当实参进行传递,那么会导致调用13行的函数失败
    return inner

@w1
def f1(a, b):
    """业务函数"""
    print(a + b)

@w1
def f2(a, b, c):
    """业务函数"""
    print(a + b + c)

f1(10, 20)
f2(10, 20, 30)

Output result:

---正在装饰---
---正在装饰---
---正在验证---
30
---正在验证---
60

5. Decorator return value 

Case:

def w1(fn):
    """装饰器函数"""
    print("---正在装饰---")
    def inner():
        print("---正在验证---")
        ret = fn()  # 保存返回来的字符串
        return ret  # 把字符串返回到20行的调用处
    return inner

@w1
def test():
    """业务函数"""
    print("---test---")
    return "这是原函数返回值"

ret = test()  # 需要用参数来接收返回值
print(ret)

Output result:

---正在装饰---
---正在验证---
---test---
这是原函数返回值

 6. Universal Decorator

 Case:

def w1(fn):
    """装饰器函数"""
    def inner(*args, **kwargs):
        print("---记录日志---")
        ret = fn(*args, **kwargs)  # 保存返回来的字符串
        return ret  # 把字符串返回到20行的调用处
    return inner

@w1
def test1():
    """不带返回值"""
    print("---test1---")

@w1
def test2():
    """带返回值"""
    print("---test2---")
    return "这是原函数返回值"

@w1
def test3(a):
    """业务函数"""
    print("---test3中的数据:%d---" % a)

ret1 = test1()
print(ret1)
ret2 = test2()
print(ret2)
ret3 = test3(10)
print(ret3)

Output result:

---记录日志---
---test1---
None
---记录日志---
---test2---
这是原函数返回值
---记录日志---
---test3中的数据:10---
None

 7. Decorator with parameters

Case:

def func_arg(arg):
    def func(funtionName):
        def func_in():
            print("输出给装饰器传入的参数:%s" % arg)
            if arg == "hello":
                funtionName()
                funtionName()
            else:
                funtionName()
        return func_in
    return func

@func_arg("hello")
def test():
    print("---test---")

@func_arg("haha")
def test2():
    print("---test2---")

test()
test2()

 Output result:

输出给装饰器传入的参数:hello
---test---
---test---
输出给装饰器传入的

 Run the analysis:

  1. First execute the func_arg("hello") function. The return result of this function is a reference to the func function;
  2. execute@func;
  3. Use @func to decorate function test

Guess you like

Origin blog.csdn.net/weixin_44793743/article/details/126558156