Advanced Python|Decorators (1)

Advanced Python|Decorators (1)

Preface

Decorators are widely used in applications such as logging and caching. Let's start with the closures explained before and explain the things about decorators.

Simple decorator

First of all, let's review the closure, which can be regarded as the nesting of functions, and the function object is returned inside the function.

def nth(exponent):
    def exponent_of(base):
        return base ** exponent
    return exponent_of

square = nth(2)
cube = nth(3)
print(square(5))
print(cube(5))

# 25 5^2
# 125 5^3

Here, what is passed in outside the closure is a parameter with a specific value. If it is passed in a function object? That completes a simple decorator.

def decorator(func):
    def wrapper():
        print('start to decorate')
        func()
        print('start to decorate')
    return wrapper

def test():
    print('welcome to decorate')

test1 = decorator(test)
test1()
#start to decorate
#welcome to decorate
#start to decorate

In this code, the test1 variable points to the function wrapper(), and the internal function wrapper() calls the test() function, so three paragraphs of text are printed at the end.

With @ Syntax Sugar, the above code can be written more concisely and more elegantly:

def decorator(func):
    def wrapper():
        print('start to decorate')
        func()
        print('start to decorate')
    return wrapper

@decorator
def test():
    print('welcome to decorate')

test()
#start to decorate
#welcome to decorate
#start to decorate

@Decorator here is equivalent to test1 = decorator(test) statement.

Decorator with parameters

If parameters need to be added to the test function, we need to add the corresponding parameters to the wrapper function:

def decorator(func):
    def wrapper(message):
        print('start to decorate')
        func(message)
        print('start to decorate')
    return wrapper

@decorator
def test(message):
    print(message)

test('hello world')
#start to decorate
#hello world
#start to decorate

But a new problem is coming. If there is a new function that also needs the decorator() decorator, but it has two parameters, what should we do?

@decorator
def test2(a,b):
    print(a+b)

In this case, we can use *args and **kwargs.

def decorator(func):
    def wrapper(*args,**kwargs):
        print('start to decorate')
        func(*args,**kwargs)
        print('start to decorate')
    return wrapper
Decorator for custom parameters

The decorator can also customize its parameters, where one more level of nesting is needed to make the internal function run multiple times.

def repeat(num):
    def decorator(func):
        def wrapper(*args,**kwargs):
            print('start to decorate')
            for i in range(num):
                func(*args,**kwargs)
            print('start to decorate')
        return wrapper
    return decorator

@repeat(3)
def test(message):
    print(message)

test('hello world')

#start to decorate
#hello world
#hello world
#hello world
#start to decorate
Interesting phenomenon

After using the decorator, there is an interesting phenomenon, that is, the meta information of the decorated function is changed.

print(test.__name__)
# wrapper

We can also use the built-in decorator @functools.wraps(func) to preserve the meta-information of the original function.

import functools

def decorator(func):
    @functools.wraps(func)
    def wrapper(*args,**kwargs):
        print('start to decorate')
        func(*args,**kwargs)
        print('start to decorate')
    return wrapper

@decorator
def test(message):
    print(message)

print(test.__name__)
# test
summary

Starting from the closure, this article explains the definition and use of the decorator. In fact, the role of the decorator is: through the decorator function, the original function can be modified without modifying the original function code.

Reference: https://cloud.tencent.com/developer/article/1529556 Advanced Python|Decorators (1)-Cloud + Community-Tencent Cloud