1. Definitions
In python, you often see the @ symbol, and the following function is a decorator. For example, when defining a class, @property is used to convert a method into an attribute of the class, which is also a decorator. The decorator can be understood as adding a behavior to the function. This behavior is a general behavior that is meaningful to your project code. Common behaviors include printing the day, printing the calculation time of the function, and for example, the parameter check we have to do this time, etc. . Adding a decorator to a function can not only increase the function, but also simplify the code and improve readability.
In addition, python has 3 built-in functions decorator , respectively @staticmethod, @classmethod and @property, where staticmethod(), classmethod() and property() are all built-in functions of Python.
role 1 decorator
Example: Calculate the runtime of a function,
import time def timer(func): """ Decorator function for timing :param func: decorated function :return: Closure function, which encapsulates custom behavior and invocation of decorated function """ def wrapper(*args, **kwargs): """ Closure function :param args: Positional parameters of the decorated function :param kwargs: keyword arguments of the decorated function :return: int,The computed result of the decorated function """ t1 = time.time() # Starting time r = func(*args, **kwargs) # Called by a decorated function t2 = time.time() # End Time cost = t2 - t1 # Calculate time print('function cost{} second'.format(cost)) return r return wrapper
The function timer we defined is a decorator function (used to wrap, placed at the outermost), this function is special, it can pass in the function as a parameter, here is our decorated function (distinguished from the decorated function) , and then the returned object is also a function, which is called a closure function. In a closure function, two things need to be done, one is to define the behavior (print the function calculation time), and the other is to call the function calculation .
After the decorator function is written, it can be used directly with the @ symbol. We define a function add that needs to be decorated. The function is to add two numbers. When using the decorator, add @timer on the line before the function.
@timer def add(x, y): time.sleep(2) return x + y
The @ symbol is the syntactic sugar of the decorator, which can be understood as the shortcut key of the decorator. If the @ symbol is not used, it is also possible to call the decorator function directly, but the syntactic sugar is more concise. The purpose of the @ symbol is to execute the following statement before the function is actually called:
add = timer(add) print(add(1, 2)) #function cost2.000091075897217 second 3
Calling the decorated function of add will pass the decorated function as a parameter to the decorated function, similar to add(1,2), where the decorated function will be called first, and then func will be executed in the decorated function
Action 2 Parameter check
As the name implies, @ in this part is used for parameter checking, such as
First, define a parameter check decorator to check whether the input parameters are consistent with the definition, otherwise an error will be reported
import collections import functools import inspect def para_check(func): """ The function parameter check decorator needs to be matched with the function annotation expression ( Function Annotations)use """ msg = 'Argument {argument} must be {expected!r},but got {got!r},value {value!r}' # Get the parameters of the function definition sig = inspect.signature(func) parameters = sig.parameters # parameter ordered dictionary arg_keys = tuple(parameters.keys()) # parameter name #Inner decorator that displays the original name of the calling function @functools.wraps(func) def wrapper(*args, **kwargs): CheckItem = collections.namedtuple('CheckItem', ('anno', 'arg_name', 'value')) check_list = [] # collect args *args The incoming parameters and the corresponding function parameter annotations, namely x: init, for i, value in enumerate(args): arg_name = arg_keys[i] anno = parameters[arg_name].annotation check_list.append(CheckItem(anno, arg_name, value)) # collect kwargs **kwargs incoming parameters and corresponding function parameter annotations for arg_name, value in kwargs.items(): anno = parameters[arg_name].annotation check_list.append(CheckItem(anno, arg_name, value)) # check type for item in check_list: if not isinstance(item.value, item.anno): error = msg.format(expected=item.anno, argument=item.arg_name, got=type(item.value), value=item.value) raise TypeError(error) return func(*args, **kwargs) return wrapper
Action 3 Annotation Expression
Annotation expression is a feature of python, which makes it possible to define the type of input parameters when the function is defined, which improves the readability of the function. Use: symbol plus parameter type to achieve
def anno(x: str, y: dict, z: int = 123): print("x type:{},y type:{},z type{}".format(type(x), type(y), type(z))) anno('123', {'a': 1}, 2) #x type:<class 'str'>,y type:<class 'dict'>,z type<class 'int'>
In the parameter type use: to define the parameter type