Python callback functions and decorators

0 Preface

>>Return to Python series article directory<<

1 callback function

In any language, there are hierarchical relationships between modules, such as:

up_file is the upper module, low_file is a lower level module

# Upper up_file
from low_file import *

def up_function():
    # code
# Lower level low_file
def low_function():
    # code

Up in the upper module_ Use lower level module low in file_ File function low_function() is very simple. Just call it directly as a local function. But if you want to lower the module low_ Use the upper module up in file_ File function up_function(), a callback is required:

Callback process:
1. Low in lower module_ File defines a function, and the input parameter must be a function

# Lower level low_file
def low_call(func):
    func()

2. Up in the upper module_ File calls this function and puts its own function as an input parameter. Be careful not to add parentheses

# Upper up_file
from A_file import *

def B_callback():
    # code

if __name__ == "__main__"
    A_call(B_callback)

This is passed into the lower function B_callback() is the callback function

2 trimmer

2.1 decorator without parameters

Using the callback function, Python designed a special function called decorator decorator

  1. First, define a decorator function decorator, and the input parameter is a callback function
  2. Define a template function wrapper in the decorator function. The input parameters are * args and * * kwargs, indicating that any form of input parameters are accepted
  3. Callback function func(*args, **kwargs) is invoked in the wrapper(*args, **kwargs) function.
  4. Perform the actions you want to attach, such as timing, up and down the callback function
  5. Decorator function decorator returns the defined wrapper function
import time

def decorator(func):
    def wrapper(*args, **kwargs):
        startTime = time.time()
        ret = func(*args, **kwargs) # Callback function
        endTime = time.time()
        msecs = (endTime - startTime)*1000
        print("time is %d ms" %msecs)
        return ret
    return wrapper

This decorator function can be added to the last line of any function definition in the form of @ decorator, and the modified function will automatically become the callback function of the decorator function during execution

@decorator
def func1(a,b):
    # code

@decorator
def func2(a,b,c):
    # code


if __name__ == '__main__':
    ret = func1(a,b)
    ret = func2(a,b,c)

Explain the process:

  1. Call a function with decorator, and perform the following syntax conversion:
  • Before conversion
@decorator
def func1(a,b):
  # code
  
func1(a,b)
  • After conversion
decorator(func1)(a, b)
  1. The result of decorator(func1) is return wrapper, so it is converted to:
wrapper(a, b)
  1. So the wrapper(a, b) function is actually executed
def wrapper(a, b):
    startTime = time.time()
    ret = func1(a, b) # Callback function
    endTime = time.time()
    msecs = (endTime - startTime)*1000
    print("time is %d ms" %msecs)
    return ret

2.2 decorator with parameters

The decorator with parameters is defined as follows, and a layer of encapsulation middle is added:

def decorator(deco_args):
    def middle(func):
        def wrapper(*args,**kwargs):
            print(deco_args)
            ret=func(*args,**kwargs)
            return ret
        return wrapper
    return middle

The process is as follows:

  1. Call a function with decorator, and perform the following syntax conversion:
  • Before conversion
@decorator(deco_args)
def func1(a,b):
  # code
  
func1(a,b)
  • After conversion
decorator(deco_args)(func1)(a, b)
  1. The result of decorator(deco_args) is return middle, so it is converted to:
middle(func1)(a, b)
  1. The result of middle(func1) execution is return wrapper, so it is converted to:
wrapper(a, b)
  1. Finally, the wrapper(a, b) function is actually executed and the parameter Deco is brought in_ args
def wrapper(a, b):
    print(deco_args)
    ret = func1(a, b) # Callback function
    return ret

2.3 preserve the properties of the original function

There is a problem when the decorator runs. During debug, the decorated function func1__ name__ Disappeared, leaving only the wrapper function in the debug message. If you want to preserve the properties of the original function, you can use functools Wraps

functools.wraps can copy the specified attributes of the original function object to the wrapper function object. By default, there are module, name and doc. The code is as follows:

from functools import wraps

def decorator(deco_args):
    def middle(func):
        @wraps(func)
        def wrapper(*args,**kwargs):
            print(deco_args)
            ret=func(*args,**kwargs)
            return ret
        return wrapper
    return middle

Keywords: Python

Added by ken72 on Tue, 04 Jan 2022 04:11:53 +0200