Adorner example
defW1 (func):definner ():Print('... Verify Permissions ...') func ()returnINNER@W1defF1 ():Print('F1 called') @w1defF2 ():Print('F2 called') F1 () F2 ()
Output Result:
... Verify permissions ... F1 called ... Verify permissions ... f2 called
When the F1,F2 function is called, validation is performed first. Through a closure function w1, call the function through the keyword @w1, the f1,f2 completed the decoration.
When the Python interpreter interprets @w1, the W1 function is called, and the name of the modified function is passed in (for example, F1), when the W1 function is executed, the inner function is returned directly, and the colleague assigns it to F1, when the F1 is not an unmodified F1. Instead, it points to the W1.inner function address. And then call the F1 function, it is good to perform permission validation first, then call the original F1 (), where the F1 is passed through the parameters F1.
Timing of execution
def W1 (fun): print (" ... Decorators Start decorating ... " ) def inner (): print ( ' ... Verify Permissions ... " ) fun () return Inner@w1 def Test (): print ( " test Span style= "COLOR: #800000" > " ) test ()
Output Result:
... Decorators Start decorating ... Verify Permissions ... test
Thus, executing @w1 is equivalent to executing the following code:
Test = W1 (test)
Two adorner execution flow and cosmetic results
defMakebold (fun):Print('----a----') definner ():Print('----1----') return '<b>'+ Fun () +'</b>' returnInnerdefmakeitalic (fun):Print('----b----') definner ():Print('----2----') return '<i>'+ Fun () +'</i>' returnInner@makebold@makeitalicdefTest ():Print('----C----') Print('----3----') return 'Hello python decorator'ret=Test ()Print(ret)
Output Result:
----b--------a--------1--------2--------C--------3----<b><i>hello python decorator</i></b >
It can be found that the second adorner (makeitalic) is used to decorate, then decorate with the first adorner (Makebold), and the first adorner (Makebold) is executed during the call, followed by the second adorner (makeitalic).
Decorating with parametric functions
defW_say (fun):"""if the original function has parameters, the closure function must keep the number of arguments consistent and pass the arguments to the original method""" defInner (name):"""if the decorated function has a row parameter, then the closure function must have parameters:p Aram Name:: return:""" Print('say inner called') Fun (name)returnInner@w_saydefHello (name):Print('Hello'+name) Hello ('Wangcai')
Output Result:
Say Inner Calledhello Wangcai
Multiple parameters or a variable parameter
defW_add (func):defInner (*args, * *Kwargs):Print('add inner called') func (*args, * *Kwargs)returnInner@w_adddefAdd (A, b):Print('%d +%d =%d'% (A, B, a +b)) @w_adddefAdd2 (A, B, c):Print('%d +%d +%d =%d'% (A, B, C, a + B +c)) Add (2, 4) ADD2 (2, 4, 6)
Output Result:
add inner called2 + 4 = 6add inner called2 + 4 + 6 = 12
Modifying a function with a return value
defW_test (func):definner ():Print('w_test inner called start') func ()Print('w_test inner called End') returninner@w_testdefTest ():Print('This is the test fun') return 'Hello'ret=Test ()Print('ret value is%s'% ret)
Output Result:
is is None
It can be found that at this time, there is no output of the test function ' Hello ', but none, that is why, it can be found that the inner function in the call to test, but not accept the return value, and do not return, then the default is None, know the reason, So let's change the code:
defW_test (func):definner ():Print('w_test inner called start') Str=func ()Print('w_test inner called End') returnStrreturninner@w_testdefTest ():Print('This is the test fun') return 'Hello'ret=Test ()Print('ret value is%s'% ret)
Output Result:
is is Hello
Adorner with parameters
defFunc_args (pre='Xiaoqiang'): defW_test_log (func):definner ():Print('... Logging ... visitor is%s'%pre) func ()returnInnerreturnW_test_log#An adorner with parameters can play at run time with different functions#executes Func_args (' Wangcai ') first, returning a reference to the W_test_log function#@w_test_log#decorate the test_log with @w_test_log@func_args ('Wangcai')defTest_log ():Print('This is test log') Test_log ()
Output Result:
is is test log
General Purpose Decorators
defW_test (func):defInner (*args, * *Kwargs): Ret= Func (*args, * *Kwargs)returnretreturninner@w_testdefTest ():Print('Test called') @w_testdeftest1 ():Print('Test1 called') return 'python'@w_testdefTest2 (a):Print('test2 called and value is%d'%a) test () test1 () test2 (9)
Output Result:
and is
Class Decorator
The adorner function is actually an interface constraint, which must accept a callable object as a parameter and then return a callable object.
In Python, general callable objects are functions, but there are exceptions. For example, if an object overrides the call method, then the object is callable.
When an object is created and executed directly, the exception is thrown, because he is not callable and cannot be executed directly, but after making the modification, it can execute the call directly, as follows
class Test (object): def __call__ (Self, *args, * *Kwargs) : Print ('callcalled'= Test ()print(t ())
Now, let's take a look at how to use the class decorator function.
classTest (object):def __init__(Self, func):Print('Test init') Print('func name is%s'% func.__name__) self.__func=funcdef __call__(Self, *args, * *Kwargs):Print('functions in the adorner') self.__func() @TestdefTest ():Print('This is test func') test ()
Output Result:
is is test func
As with the previous principle, when the Python interpreter executes to @test, the current test function is passed as a parameter to the test object, the Init method is called, and the test function is pointed to the created Test object, and then when the test () is executed, The call method is actually called directly to the object being created.
Python decorator @property