Multiple decorators in Python and multiple decorators in Python
Multiple decorators are used to modify the same object]
1. the decorator has no parameters:
Copy codeThe Code is as follows:
>>> Def first (func ):
Print '% s () was post to first ()' % func. func_name
Def _ first (* args, ** kw ):
Print 'Call the function % s () in _ first (). '% func. func_name
Return func (* args, ** kw)
Return _ first
>>> Def second (func ):
Print '% s () was post to second ()' % func. func_name
Def _ second (* args, ** kw ):
Print 'Call the function % s () in _ second (). '% func. func_name
Return func (* args, ** kw)
Return _ second
>>> @ First
@ Second
Def test (): return 'Hello world'
Test () was post to second ()
_ Second () was post to first ()
>>> Test ()
Call the function _ second () in _ first ().
Call the function test () in _ second ().
'Hello world'
>>>
In fact, it is equivalent to the following code:
Copy codeThe Code is as follows:
>>> Def test ():
Return 'Hello world'
>>> Test = second (test)
Test () was post to second ()
>>> Test
<Function _ second at 0x0000000000000d3c8>
>>> Test = first (test)
_ Second () was post to first ()
>>> Test
<Function _ first at 0x0000000000000d358>
>>> Test ()
Call the function _ second () in _ first ().
Call the function test () in _ second ().
'Hello world'
>>>
2. the decorator has the following parameters:
Copy codeThe Code is as follows:
>>> Def first (printResult = False ):
Def _ first (func ):
Print '% s () was post to _ first ()' % func. func_name
Def _ first (* args, ** kw ):
Print 'Call the function % s () in _ first (). '% \
Func. func_name
If printResult:
Print func (* args, ** kw), '# print in _ first ().'
Else:
Return func (* args, ** kw)
Return _ first
Return _ first
>>> Def second (printResult = False ):
Def _ second (func ):
Print '% s () was post to _ second ()' % func. func_name
Def _ second (* args, ** kw ):
Print 'Call the function % s () in _ second (). '% \
Func. func_name
If printResult:
Print func (* args, ** kw), '# print in _ second ().'
Else:
Return func (* args, ** kw)
Return _ second
Return _ second
>>> @ First (True)
@ Second (True)
Def test ():
Return 'Hello world'
Test () was post to _ second ()
_ Second () was post to _ first ()
>>> Test ()
Call the function _ second () in _ first ().
Call the function test () in _ second ().
Hello world # print in _ second ().
None # print in _ first ().
>>>
As shown above, after 35th rows are output, _ second () is called, while _ second () calls test () and print test (), and then returns _ first () and the print content of this print statement is None returned by _ second ().
It is equivalent:
Copy codeThe Code is as follows:
>>> Def test ():
Return 'Hello world'
>>> Test = second (True) (test)
Test () was post to _ second ()
>>>
>>> Test
<Function _ second at 0x0000000000000d2e8>
>>> Test = first (True) (test)
_ Second () was post to _ first ()
>>> Test
<Function _ first at 0x0000000003344c6>
>>>
3. Application of Multiple decorations:
For example, if you are a project manager, you require that each code block have a parameter check ArgsType and a responsibility check ResponsibilityRegister. In this way, you need two decorators to supervise the code block.
Copy codeThe Code is as follows:
# Coding = UTF-8
Import OS, sys, re
From collections import OrderedDict
Def ArgsType (* argTypes, ** kwTypes ):
U''' ArgsType (* argTypes, ** kwTypes)
Options = [('opt _ usetypeofdefavalue value', False)]
The following is a function-related switch, not a Type Validation-related keyword parameter, all options:
Opt_usetypeofdefadefavalue => bool: False. If it is True
The type of a parameter that uses its default value
'''
Def _ ArgsType (func ):
# Determine all parameter names
ArgNames = func. func_code.co_varnames [: func. func_code.co_argcount]
# Determine all default parameter
Defaults = func. func_defaults
If defaults:
Defaults = dict (zip (argNames [-len (defaults):], defaults ))
Else: defaults = None
# Put forward all "options keyword Parameters" in "parameter type keyword Parameters"
Options = dict ()
For option, default in [('opt _ usetypeofdefavalue value', False)]:
Options [option] = kwTypes. pop (option, default)
# The total length of argTypes and kwTypes should be consistent with that of argNames.
If len (argTypes) + len (kwTypes)> len (argNames ):
Raise Exception ('too much types to check % s (). '% func. func_name)
# Keys in all kwTypes cannot overwrite the names occupied in argTypes
If not set (argNames [len (argTypes):]). issuperset (
Set (kwTypes. keys ())):
Raise Exception ('there is some key in kwTypes '+
'Which is not in argNames .')
# Determine the types that all parameters should have
Types = OrderedDict ()
For name in argNames: types [name] = None
If len (argTypes ):
For I in range (len (argTypes )):
Name = argNames [I]
Types [name] = argTypes [I]
Else:
For name, t in kwTypes. items ():
Types [name] = t
If len (kwTypes ):
For name, t in kwTypes. items ():
Types [name] = t
# About the type of default parameter
If options ['opt _ usetypeofdefavalue value']:
For k, v in defaults. items ():
# If the type of the default parameter is not specified separately, use
# Default parameter's default value type
If types [k] = None:
Types [k] = type (v)
Def _ ArgsType (* args, ** kw ):
# Order the args
Args = OrderedDict ()
# Init keys
For name in argNames: Args [name] = None
# Init default values
If defaults is not None:
For k, v in defaults. items ():
Args [k] = v
# Fill in all args
For I in range (len (args )):
Args [argNames [I] = args [I]
# Fill in all keyword args
For k, v in kw. items ():
Args [k] = v
# Check if there is some None in the values
If defaults = None:
For k in Args:
If Args [k] = None:
If defaults = None:
Raise Exception ('% s () needs % r parameter,' +
'Which was not given') % (func. func_name, k ))
Else:
If not defaults. has_key (k ):
Raise Exception ('parameter % r of % s () is '+
'Not a default parameter ') % \
(K, func. func_name ))
# Check all types
For k in Args:
If not isinstance (Args [k], types [k]):
Raise TypeError ('parameter % r of % s () must be '+
'A % r object, but you post: % R') % \
(K, func. func_name, types [k], Args [k])
Return func (* args, ** kw)
Return _ ArgsType
Return _ ArgsType
Def ResponsibilityRegister (author ):
Def _ ResponsibilityRegister (func ):
Def _ ResponsibilityRegister (* args, ** kw ):
Try:
Return func (* args, ** kw)
Failed t Exception as e:
Print ("Something is wrong, It's % s responsibility." % \
Author). center (80 ,'*')
Raise e
Return _ ResponsibilityRegister
Return _ ResponsibilityRegister
@ ResponsibilityRegister ('Kate ')
@ ArgsType (str, int)
Def left (Str, Len = 1 ):
Return Str [: Len]
Print 'good calling :'
Print left ('Hello world', 8)
Print 'bad calling :'
Print left (3, 7)
There is no document here, so the caller does not know that it is Kate's responsibility to use an incorrect call, resulting in an error.
As in the above case, when there are two mutually unrelated checks on the code, you can use multiple decorators.