Python decorator usage example summary, python decorator usage example
This document describes how to use the Python decorator. We will share this with you for your reference. The details are as follows:
I. What is the decorator?
The python decorator is essentially a Python function that allows other functions to add additional functions without any code changes. The return value of the decorator is also a function object. In short, the decorator is a function used to return functions.
It is often used in scenarios with specific requirements, such as log insertion, performance testing, transaction processing, caching, and permission verification. The decorator is an excellent design for solving such problems. With the decorator, we can extract a large number of identical code irrelevant to the function itself and continue to reuse it.
In summary, the purpose of the decorator is to add additional functions to existing objects.
Ii. Why do you need a decorator?
1. Let's look at a simple example:
def foo():print('i am foo')
2. Increase demand
Now there is a new requirement to record the execution log of the function, so add the log code to the Code:
def foo(): print('i am foo') print("foo is running")
3. There are demands
Suppose there are now 100 functions that need to be added, and the need to print logs before executing these one hundred functions may be added in the future. What should I do? Are there any other changes?
Of course not, this will lead to a lot of identical code. To reduce repeated code writing, we can do this and redefine a function: Specially processing logs, after the logs are processed, execute the real business code.
def use_logging(func): print("%s is running" % func.__name__) func()def bar(): print('i am bar')use_logging(bar)#result:#bar is running#i am bar
With the preceding use_logging function, we have added the log function. No matter how many functions need to add logs or modify the log format, we only need to modify the use_logging function and execute use_logging (decorated function) it achieves the desired effect.
def use_logging(func): print("%s is running" % func.__name__) return func@use_loggingdef bar(): print('i am bar')bar()
3. Basic decorators
1. decorator syntax sugar
Python provides @ symbol as the syntactic sugar of the decorator, which makes it easier for us to use decorative functions. However, syntax sugar requires that the decoration function must return a function object. Therefore, we wrap the above func functions with nested functions and return.
The decorator executes the decoration function use_loggin and returns the decorated function bar. Therefore, when bar () is called, two functions are executed. Equivalent to use_logging (bar )()
def use_logging(func): def _deco(): print("%s is running" % func.__name__) func() return _deco@use_loggingdef bar(): print('i am bar')bar()
2. Decoration of functions with Parameters
Now our parameters need to be passed in two parameters and calculated values, so we need to modify the inner function and pass in our two parameters a and B, which is equivalent to use_logging (bar) (1, 2)
def use_logging(func): def _deco(a,b): print("%s is running" % func.__name__) func(a,b) return _deco@use_loggingdef bar(a,b): print('i am bar:%s'%(a+b))bar(1,2)
The number and type of parameters of the decoration function are different. Do we need to modify the decoration device every time? This is of course not scientific, so we use python's variable length parameters * args and ** kwargs to solve our parameter problems.
3. The number of function parameters is unknown.
The decorator version without parameters. This format is applicable to decorator without parameters.
After the following modifications, we have adapted parameters of various lengths and types. The decorator of this version can have any type of non-parameter functions.
def use_logging(func): def _deco(*args,**kwargs): print("%s is running" % func.__name__) func(*args,**kwargs) return _deco@use_loggingdef bar(a,b): print('i am bar:%s'%(a+b))@use_loggingdef foo(a,b,c): print('i am bar:%s'%(a+b+c))bar(1,2)foo(1,2,3)
4. decorator with Parameters
Parameter-based decorators. This format is applicable to parameter-based decorators.
In some cases, we need to add parameters to the decorator, so we need to write a high-order function that returns a decorator, which is more complicated to write. For example:
#! /Usr/bin/env python #-*-coding: UTF-8-*-# _ author _ = "TKQ" def use_logging (level): def _ deco (func ): def _ deco (* args, ** kwargs): if level = "warn": print "% s is running" % func. _ name _ return func (* args, ** kwargs) return _ deco @ use_logging (level = "warn") def bar (a, B ): print ('I am bar: % s' % (a + B) bar (1, 3) # equivalent to use_logging (level = "warn") (bar) (1, 3)
5. functools. wraps
The code is greatly reused with the decorator, but one drawback is that the metadata of the original function is missing, such as docstring, _ name _, and parameter list of the function. Let's look at the example first:
Def use_logging (func): def _ deco (* args, ** kwargs): print ("% s is running" % func. _ name _) func (* args, ** kwargs) return _ deco @ use_loggingdef bar (): print ('I am bar') print (bar. _ name _) bar () # bar is running # I am bar # _ deco # The function name is changed to _ deco instead of bar, this may cause problems when using the reflection feature. Therefore, functools. wraps is introduced to solve this problem.
Use functools. wraps:
Import functoolsdef use_logging (func): @ functools. wraps (func) def _ deco (* args, ** kwargs): print ("% s is running" % func. _ name _) func (* args, ** kwargs) return _ deco @ use_loggingdef bar (): print ('I am bar') print (bar. _ name _) bar () # result: # bar is running # I am bar # bar. This result is what we want. OK!
6. implement self-adaptation of decorator with or without Parameters
Import functoolsdef use_logging (arg): if callable (arg): # judge whether the input parameter is a function. The decorator without parameters calls this branch @ functools. wraps (arg) def _ deco (* args, ** kwargs): print ("% s is running" % arg. _ name _) arg (* args, ** kwargs) return _ deco else: # Call this branch def _ deco (func): @ functools. wraps (func) def _ deco (* args, ** kwargs): if arg = "warn": print "warn % s is running" % func. _ name _ return func (* args, ** kwargs) return _ deco @ use_logging ("warn") # @ use_loggingdef bar (): print ('I am bar') print (bar. _ name _) bar ()
Iii. Class decorator
The class decorator can be used to achieve the effect of the parameter decorator, but the implementation is more elegant and concise, and can be flexibly expanded through inheritance.
1. Class decorator
Class loging (object): def _ init _ (self, level = "warn"): self. level = level def _ call _ (self, func): @ functools. wraps (func) def _ deco (* args, ** kwargs): if self. level = "warn": self. every y (func) return func (* args, ** kwargs) return _ deco def every Y (self, func): # logit only logs are typed, no other print "% s is running" % func. _ name __@ loging (level = "warn") # Run the _ call _ method def bar (a, B): print ('I am bar: % s' % (a + B) bar (1, 3)
2. inherit the extended class decorator
Class email_loging (Loging): ''' an implementation version of loging. You can send an email to the Administrator ''' def _ init _ (self, email = 'admin @ myproject.com ', * args, ** kwargs): self. email = email super (email_loging, self ). _ init _ (* args, ** kwargs) def notify y (self, func): # send an email to self. email print "% s is running" % func. _ name _ print "sending email to % s" % self. email @ email_loging (level = "warn") def bar (a, B): print ('I am bar: % s' % (a + B) bar (1, 3)