Python decorator learning and Practical Use Cases
Preface
I was reading the Flask framework a few days ago. I don't really understand it. I came back to the homework of the decorator. I have read a lot of articles about the decorator. I will sort out the methods and examples that suit my own ideas and share them with you.
- app = Flask(__name__)
- @app.route("/")
- def hello():
- return "Hello World!"
1. What is the decorator?
The decorator is an advanced syntax in Python. The main function is to process a function, method, or class. It adds additional functions to existing objects to improve code readability.
The decorator is a design pattern used in scenarios with cut-plane requirements. It is typical for log insertion, performance testing, and transaction processing.
2. decorator syntax
The decorator syntax is as follows:
The current Python decorator syntax is as follows:
- @ Dec2
- @ Dec1
- Def func (arg1, arg2 ,...):
- ....
- Return funx
-
- The above code is equivalent:
-
- Def func (arg1, arg2 ,...):
- Pass
- Func = dec2 (dec1 (func ))
Decorator can be defined in the format of def.The decorator receives a callable object as the input parameter and returns a new callable object.
The modifier creates a new callable object, that is, the function funx returned by return. In the newly added function, you can add the functions we need, the original function is implemented by calling the original function.
3. Use of decorator
3.1 decorator without Parameters
Defining the decorator is very simple:
- Def deco (func ):
- "A parameter is required when a decorator declaration is called without a parameter. This parameter will receive the method to be decorated """
- Print "before myfunc () called ."
- Func ()
- Print "after myfunc () called ."
- Return func
-
- @ Deco
- Def myfunc ():
- Print "myfunc) called ."
-
-
- Myfunc ()
- Myfunc ()
After the decorator is defined, you can use it. The above decorator has a problem when it is used, that is, it is called only for the first time, and the original function is executed once more. The execution output is as follows:
- Before myfunc () called.
- Myfunc () called.
- After myfunc () called.
- Myfunc () called. -- output of multiple function executions once
- Myfunc () called. -- the second call, the modifier does not take effect
To ensure that the new function is called every time, use the following method to define the decorator:
- Def deco (func ):
- "A parameter is required when a decorator declaration is called without a parameter. This parameter will receive the method to be decorated """
- Def _ deco ():
- Print "before myfunc () called ."
- Func ()
- Print "after myfunc () called ."
- # Return func does not need to return func
- Retrun _ deco
- @ Deco
- Def myfunc ():
- Print "myfunc) called ."
- Return 'OK'
- Myfunc ()
- Myfunc ()
Function output is as follows:
- before myfunc() called.
- myfunc() called.
- after myfunc() called.
- before myfunc() called.
- myfunc() called.
- after myfunc() called.
In this way, you can see that the decorator is called every time.
3.2 decorator with Parameters
- def deco(func):
- def _deco(a, b):
- print("before myfunc() called.")
- ret = func(a, b)
- print(" after myfunc() called. result: %s" % ret)
- return ret
- return _deco
-
- @deco
- def myfunc(a, b):
- print(" myfunc(%s,%s) called." % (a, b))
- return a + b
-
- myfunc(1, 2)
- myfunc(3, 4)
Output:
- before myfunc() called.
- myfunc() called.
- After myfunc() called. result: 3
- before myfunc() called. myfunc() called. After myfunc() called. result: 7
The parameters and return values of nested functions are the same as those of the original function. The decoration function returns the nested packaging function.
3.3 decorator with Parameters
- Def decoWithArgs (arg ):
- "Because the decorator function with parameters only uses the parameters in use when calling, rather than receiving the decorated functions as parameters,
- Therefore, a decorator function must be returned to encapsulate and process the decorated function """
- Def newDeco (func): # define a new decorator Function
- Def replaceFunc (): # define an embedded function in the decorator function to encapsulate specific operations.
- Print "Enter decorator % s" % arg # perform additional operations
- Return func () # Call the decorated Function
- Return replaceFunc
- Return newDeco # return a new decorator Function
-
- @ DecoWithArgs ("demo ")
- Def MyFunc (): # decoWithArgs
- Print "Enter MyFunc"
-
- MyFunc () # Call the decorated Function
Output:
Nter decorator demo
Enter MyFunc
This situation applies to the case where the original function has no parameters and printing is added.A common application is to add function printing logs.
3.4 describe functions with uncertain number of parameters
The following is an example of asynchronous sending of mail. The parameter data of the function is determined. The decorator implements asynchronous sending of the mail sending function.
- from threading import Thread
-
- def async(f):
- def wrapper(*args, **kwargs):
- thr = Thread(target = f, args = args, kwargs = kwargs)
- thr.start()
- return wrapper
-
- @async
- def send_async_email(msg):
- mail.send(msg)
-
- def send_email(subject, sender, recipients, text_body, html_body):
- msg = Message(subject, sender = sender, recipients = recipients)
- msg.body = text_body
- msg.html = html_body
- send_async_email(msg)
In addition, this decorator can be used for all functions that require asynchronous processing, so as to achieve very good code reuse.
3.5 let the decorator carry Class Parameters
- Class locker:
- Def _ init _ (self ):
- Print ("locker. _ init _ () shocould be not called .")
- @ Staticmethod
- Def acquire ():
- Print ("locker. acquire () called. This is a static method )")
- @ Staticmethod
- Def release ():
- Print ("locker. release () called. No object instance is required )")
- Def deco (cls ):
- ''' Cls must implement the acquire and release static methods '''
- Def _ deco (func ):
- Def _ deco ():
- Print ("before % s called [% s]." % (func. _ name __, cls ))
- Cls. acquire ()
- Try:
- Return func ()
- Finally:
- Cls. release ()
- Return _ deco
- Return _ deco
- @ Deco (locker)
- Def myfunc ():
- Print ("myfunc () called .")
- Myfunc ()
- Myfunc ()
Output:
- before myfunc called [__main__.locker].
- locker.acquire() called.(this is staticmethon)
- myfunc() called.
- locker.release() called.(do't need object )
-
- before myfunc called [__main__.locker].
- locker.acquire() called.(this is staticmethon)
- myfunc() called.
- locker.release() called.(do't need object )
Summary
After applying the decoration method to a method, we actually changed the entry point of the function code block referenced by the decoration function name, point it back to the function entry point returned by the decoration method. Therefore, we can use decorator to change the functions of an original function, add various operations, or completely change the original implementation.
References
Thanks to the following great gods:
Http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html
Http://www.cnblogs.com/Jifangliang/archive/2008/07/22/1248313.html
Http://www.cnblogs.com/vamei/archive/2013/02/16/2820212.html