Using Python decorator

Time:2020-11-21

Decorator pattern is one of the commonly used software design patterns. With this design pattern, we can assign new responsibilities to existing objects without modifying any underlying code. In Python, decorators can be used to implement decorator mode simply.

PS note: many people will encounter a variety of vexation problems in the process of learning python, and it is easy to give up if no one answers. For this small editor built a python stack free Q & A. skirt: seven clothes, nine seven seven bar and five (the number of homophony) conversion can be found, do not understand the problem has the old driver to solve, there is the latest Python practical course, no need to go down, supervise each other and make progress together!

1.1 passing functions as parameters

stayC/C++A function pointer can pass a function as an argument to another function. And in thepythonFunction is also a kind of object. Function can be referenced, passed in as parameter directly, and as element of container object. In Python, you can use the following methods to implement decorator mode:

#!/usr/bin/env python3.6
# -*- coding: utf-8 -*-

def add(x, y):
    result = x+y
    return result

def log(func):
    def wrapper(*args, **kwargs):
        result = func(*args)
        print(func.__name__,'has been called\n')
        return result
    return wrapper

if __name__ == '__main__':
    print(log(add)(1,2))

In the above code,logFunction takes the function to be decorated as an argument and returns the function object. The parameters of the returned function are variable*argsAnd**kwargs*argsParameters are encapsulated astuple**kwargsParameters will be encapsulated into dictionary objects) to adapt to different parameters of different functions and ensure the universality.

1.2 decorator

The above implementation method is a bit complicated. All codes calling decorated functions need to be modified accordingly, which naturally does not conform to the concise and easy-to-read features of Python. Therefore, python gives the corresponding syntax sugar to increase readability and ease of use, which is “decorator”.

#!/usr/bin/env python3.6
# -*- coding: utf-8 -*-

from functools import wraps

def log(func):
    #@wraps(func)
    def wrapper(*args, **kwargs):
        result = func(*args)
        print(func.__name__,'has been called')
        return result
    return wrapper

#Equivalent to add = log (add)
@log
def add(x, y):
    result = x+y
    return result

if __name__ == '__main__':
    print(add(1,2))
    print(add.__name__)

The operation is as follows

>>print(add(1,2))
add has been called
3
>>print(add.__name__)
wrapper

However, the above method also has defects. The metadata (such as name, document string, annotation and parameter signature) of the original function add will be lost. To avoid defects, whenever you define a decorator, you should use itfunctoolsIn the library@wrapsDecorator to annotate the underlying wrapper function (comment part of the code).@wrapsOne important feature is that it allows you to go through attributes__wrapped__Direct access to the wrapped function.
Operation after improvement

>>print(add(1,2))
add has been called
3
>>print(add.__name__)
add

1.3 removing the decorator

When the decorator has been applied to a function and you want to undo it, you can access__wrapped__Property to access the original function

orig_add = add.__wrapped__
orig_add(1,2)

But if more than one decorator is used__wrapped__Properties can become uncontrollable and should be avoided.
If there are the following codes:

#!/usr/bin/env python3.6
# -*- coding: utf-8 -*-

import functools
import time

def metric(func):
    @functools.wraps(func)
    def wrapper(*args,**kv):
        print('Decorator1')
        f = func(*args,**kv)
        return f
    return wrapper

def logging(func):
    @functools.wraps(func)
    def wrapper(*args,**kv):
        print('Decorator2')
        f = func(*args,**kv)
        return f
    return wrapper

@metric
@logging
def normalize(name):
    sName = name[0:1].upper() + name[1:].lower()
    print(sName)

if __name__ == '__main__':
    normalize('heLlO')
    normalize.__wrapper__('')

The operation is as follows

>>normalize('helLo')
Decorator1
Decorator2
Hello
>>normalize.__wrapped__('world')
Decorator2
World

1.4 define decorators with parameters

from functools import wraps

def log(text):
    def decorator(func):
        @wraps(func) 
        def wrappering(*args,**kv):
            print('%s %s():'%(text,func.__name__))
            return func(*args,**kv)
        return wrappering
    return decorator

@log('run')
def normalize(name):
    sName = name[0:1].upper() + name[1:].lower()
    print(sName)

Decorator functions can take parameters. The outermost function will pass the parameters to the inner decorator function, i.ewrapperingFunction can be usedlogOf the passed in parameter of.
Decorator processing is equivalent to the following:

normalize = log('run')(normalize)

Summary note: many people will encounter a variety of vexation problems in the process of learning python, and it is easy to give up if no one answers. For this small editor built a python stack free Q & A. skirt: seven clothes, nine seven seven bar and five (the number of homophony) conversion can be found, do not understand the problem has the old driver to solve, there is the latest Python practical course, no need to go down, supervise each other and make progress together!

The text and pictures of this article are from the Internet and my own ideas. They are for study and communication only. They do not have any commercial use. The copyright belongs to the original author. If you have any questions, please contact us in time for handling.