Python's adorner decorator's learning notes

Source: Internet
Author: User
Tags aop wrapper

1. What is this stuff?

It's not too clear, it says, like Java AOP (Aspect oriented programming, aspect-oriented programming), I know nothing about AOP. According to my repeated consideration of the use of many examples, I think it is similar to the concept of the front and back keys in programming semantics (@pre and @post in Eiffel). Of course you can do more things in the adorner than the front key and the back key, such as introducing a log, increasing the timing logic to detect performance, and increasing the transaction capacity of the function.


In fact, the adorner is actually a function, a function to wrap the function, return a modified function object, reassign it to the original identifier, and permanently lose access to the original function object.


2. Adorner syntax

(1) No parameter adorner

[Python] View plain copy
def deco (func):
Print Func
return func
@deco
def foo ():p
Foo ()

The first function, Deco, is an ornamental function whose argument is the decorated function object. We can "decorate" the incoming function object in the Deco function, and then return the object (remember to return it, otherwise there will be no function available where the outside call Foo is). Actually at this point Foo=deco (foo))

I wrote a small example of a check function that has no documented documentation:

[Python] View plain copy
def deco_functionneeddoc (func):
If func.__doc__ = None:
Print Func, "has no __doc__, it ' s a bad habit."
Else
Print func, ': ', func.__doc__, '. '
return func
@deco_functionNeedDoc
def f ():
print ' F () do something '
@deco_functionNeedDoc
def g ():
' I have a __doc__ '
print ' g () do something '
F ()
G ()

(2) has the parameter to decorate the device

[CPP] View plain copy
def decomaker (ARG):
' Usually there is a certain requirement for ARG '
"" "because the decorator function with parameters uses only the parameters of the application when it is invoked
Instead of receiving the decorated function as a parameter, you must create it inside
a function
"""
def Newdeco (func): #定义一个新的decorator函数
Print Func, arg
return func
Return Newdeco
@decomaker (Deco_args)
def foo ():p
Foo ()
The first function, Decomaker, is a decorative function, and its parameters are used to enhance the "enhanced decoration". Because this function is not a decorated function object, you must create at least one function to accept the decorated function internally, and then return the object (actually Foo=decomaker (ARG) (in fact)

I really can't think of a good example, or see less Ah, had to borrow the example of synchronous lock:

[Python] View plain copy
def synchronized (lock):
"" "Lock Sync Decoration method
! Lock must implement the acquire and release methods
"""
def sync_with_lock (func):
def new_func (*args, **kwargs):
Lock.acquire ()
Try
return func (*args, **kwargs)
Finally
Lock.release ()
New_func.func_name = Func.func_name
new_func.__doc__ = func.__doc__
Return New_func
Return Sync_with_lock
@synchronized (__locker)
def update (data):
"" Update Scheduled Tasks ""
tasks = Self.get_tasks ()
Delete_task = None
For task in tasks:
If task[plantask.id] = = Data[plantask.id]:
Tasks.insert (Tasks.index (Task), data)
Tasks.remove (Task)
Delete_task = Task
R, msg = Self._refresh (tasks, Delete_task)
return r, MSG, Data[plantask.id]
The call is still Updae (data).

You can also use multiple adorners together:

[Python] View plain copy
@synchronized (__locker)
@deco_functionNeedDoc
def f ():
print ' F () do something '
After learning the feeling is always: the adorner can make the function light, more importantly, the function of the constraints placed at the interface to make the intention more clear, without increasing the burden on the caller.


This is the content which is introduced in the Python Study group, now learns to sell, the practice is the good study way.


The first step: The simplest function to prepare additional features


#-*-CODING:GBK-*-
"Example 1: The simplest function, indicating that two times have been invoked

Def myfunc ():
Print ("MyFunc () called.")

MyFunc ()
MyFunc ()

Step two: Use the decoration function to attach additional functionality before and after the function is executed


#-*-CODING:GBK-*-
' Example 2: Replace function (decoration)
The parameters of the decoration function are decorated function objects, returning the original function object
The material Statement of ornament: MyFunc = Deco (MyFunc)

def deco (func):
Print ("Before MyFunc () called.")
Func ()
Print ("After MyFunc () called.")
return func

Def myfunc ():
Print ("MyFunc () called.")

MyFunc = Deco (MyFunc)

MyFunc ()
MyFunc ()

Step three: Use the syntax sugar @ to decorate the function


#-*-CODING:GBK-*-
"Example 3: Use the syntax sugar @ to decorate the function, equivalent to" MyFunc = Deco (MyFunc) "
But found that the new function was invoked only for the first time, and the original function called one more time.

def deco (func):
Print ("Before MyFunc () called.")
Func ()
Print ("After MyFunc () called.")
return func

@deco
Def myfunc ():
Print ("MyFunc () called.")

MyFunc ()
MyFunc ()

Step Fourth: Use the inline wrapper function to make sure that each new function is called

#-*-CODING:GBK-*-
"Example 4: Use the inline wrapper function to make sure that every new function is called.
The inline wrapper function has the same formal parameter and return value as the original function, and the adorner returns the embedded wrapper function object '

def deco (func):
Def _deco ():
Print ("Before MyFunc () called.")
Func ()
Print ("After MyFunc () called.")
# do not need to return func, you should actually return the return value of the original function
Return _deco

@deco
Def myfunc ():
Print ("MyFunc () called.")
Return ' OK '

MyFunc ()
MyFunc ()

Step Fifth: Decorate the function with parameters

#-*-CODING:GBK-*-
"Example 5: To decorate a function with parameters,
The inline wrapper function has the same formal parameter and return value as the original function, and the adorner returns the embedded wrapper function object '

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)

Step Sixth: Decorate a function with an indeterminate number of parameters

#-*-CODING:GBK-*-
"Example 6: To decorate a function with an indeterminate number of parameters,
Parameters (*args, **kwargs), automatic adaptation of parameters and named arguments ' "

def deco (func):
def _deco (*args, **kwargs):
Print ("before%s called."% func.__name__)
ret = func (*args, **kwargs)
Print ("after%s called.") Result:%s% (func.__name__, ret))
return ret
Return _deco

@deco
Def MyFunc (A, B):
Print ("MyFunc (%s,%s) called."% (A, b))
Return a+b

@deco
Def MYFUNC2 (A, B, c):
Print ("Myfunc2 (%s,%s,%s) called."% (A, B, c))
Return A+b+c

MyFunc (1, 2)
MyFunc (3, 4)
MYFUNC2 (1, 2, 3)
MYFUNC2 (3, 4, 5)

Seventh step: Let the adorner take the parameter

#-*-CODING:GBK-*-
"Example 7: On the basis of example 4, let the adorner take a parameter,
Compared with the previous example, there is a layer of packaging in the outer layer.
The decorative function name should actually be more meaningful.

def deco (ARG):
def _deco (func):
Def __deco ():
Print ("before%s called [%s]."% (func.__name__, ARG))
Func ()
Print ("After%s called [%s]."% (func.__name__, ARG))
Return __deco
Return _deco

@deco ("MyModule")
Def myfunc ():
Print ("MyFunc () called.")

@deco ("Module2")
Def MYFUNC2 ():
Print ("Myfunc2 () called.")

MyFunc ()
MYFUNC2 ()

Eighth step: Let the adorner with class parameters

#-*-CODING:GBK-*-
' Example 8: Adorner with class parameter '

Class Locker:
def __init__ (self):
Print ("locker.__init__ () should is not called.")

@staticmethod
def acquire ():
Print ("Locker.acquire () called. (This is a static method)")

@staticmethod
Def release ():
Print ("Locker.release () called. (no object instance required)")

def deco (CLS):
' The 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 ()

Nineth Step: Adorners with class parameters, and split public classes into other py files, while demonstrating the application of multiple adorners to a function

#-*-CODING:GBK-*-
' mylocker.py: public class for example 9.py '

Class Mylocker:
def __init__ (self):
Print ("mylocker.__init__ () called.")

@staticmethod
def acquire ():
Print ("Mylocker.acquire () called.")

@staticmethod
def unlock ():
Print ("Mylocker.unlock () called.")

Class Lockerex (Mylocker):
@staticmethod
def acquire ():
Print ("Lockerex.acquire () called.")

@staticmethod
def unlock ():
Print ("Lockerex.unlock () called.")

def lockhelper (CLS):
' The CLS must implement the acquire and release static methods '
def _deco (func):
def __deco (*args, **kwargs):
Print ("before%s called."% func.__name__)
Cls.acquire ()
Try
return func (*args, **kwargs)
Finally
Cls.unlock ()
Return __deco
Return _deco


#-*-CODING:GBK-*-
' ' Example 9: adorners with class parameters and split public classes into other py files
also demonstrates applying multiple adorners to a function "
 
from Mylocker Imp ORT *
&NBSP
Class Example:
    @lockhelper (mylocker)
    def myfunc (self ):
        Print ("MyFunc () called.")
 
    @lockhelper (mylocker)
    @lockhelper (Lockerex)
     def myfunc2 (self, A, b):
        Print ("Myfunc2 () called.")
        return a + b
 
If __name__== "__main__":
  & nbsp A = Example ()
    a.myfunc ()
    print (A.myfunc ())
    print ( A.MYFUNC2 (1, 2))
    print (A.MYFUNC2 (3, 4))

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.