ArticleDirectory
- 1. Origin
- 2. Make the code more elegant.
- 3. Make the code more elegant.
- 4. Add Parameters
- 5. Decorated functions with return values
- 6. apply multiple decorators
- 7. Flexible Use
To understand Python's decorator, you must first know that the function is also an object in Python, so you can
- Copy a function to a variable
- Use a function as a parameter
- Returns a function.
In python, functions give variables the same usage as first-class citizens, that is, high order functions ). All magic comes from this.
1. Origin
We want to output debugging information in the function login. We can do this.
Def login (): Print ('in login') def printdebug (func): Print ('Enter the login') func () print ('Exit the login ') printdebug (LOGIN)
This method is annoying because it is called through printdebug every time login is called, but after all this is feasible.
2. Let Code More elegant
Since a function can be used as a return value and can be assigned to a variable, we can make the code more elegant.
Def login (): Print ('in login') def printdebug (func): def _ decorator (): Print ('Enter the login') func () print ('Exit the login') return _ decorator # function as return valuedebug_login = printdebug (LOGIN) # function assign to variabledebug_login () # execute the returned Function
In this way, we only need to call debug_login every time. This name is more intuitive. Bind the original two functions printdebug and login to debug_login. This coupling is called cohesion :-).
3. Make the code more elegant.
Printdebug and login are combined by the debug_login = printdebug (LOGIN) clause. This clause seems redundant. Can you add a label to Define Login, so as to combine printdebug and login?
From the perspective of statement organization, the above code is very difficult to look beautiful. The Python solution is to provide a syntax sugar and combine them with a @ symbol.
Def printdebug (func): def _ decorator (): Print ('Enter the login') func () print ('Exit the login ') return _ decorator @ printdebug # combine the printdebug and logindef login (): Print ('in login') login () # Make the calling point more intuitive
We can see that decorator is a function that uses functions as parameters and returns functions. Through improvement, we can get:
- For a shorter code, place the combination point in the Function Definition
- Function Name of the original function is not changed
When the python interpreter finds a login call, it converts login to printdebug (LOGIN )(). That is to say, the function _ decorator is actually executed.
4. Add Parameters
1. the login function has parameters.
The login function may have parameters, such as passing user information during login. In other words, we need to call login as follows:
Login (User)
Python directly transmits the login parameter to the _ decorator function. We can directly use the user variable in _ decorator:
Def printdebug (func): def _ decorator (User): # Add parameter receive the user informationprint ('Enter the login') func (User) # Pass user to loginprint ('Exit the login') return _ decorator @ printdebug def login (User): Print ('in login: '+ User) login ('jatsz ') # arguments: jatsz
Let's explain the call process of login ('jatsz:
[Decorated] Login ('jatsz ') => printdebug (LOGIN) ('jatsz') => _ decorator ('jatsz ') => [Real] Login ('jatsz ')
2. the decorator has parameters.
When defining a decorator, we can also include parameters. For example, if we use decorator like this, we pass in a parameter to specify the debug level.
@ Printdebug (Level = 5) def login pass
To receive parameters from the decorator, we wrap a function on the original decorator to receive parameters:
Def printdebug_level (level): # Add wrapper to recevie decorator's parameterdef printdebug (func): def _ decorator (User): Print ('Enter the login, and debug level is: '+ STR (level) # print debug levelfunc (User) print ('Exit the login') return _ decorator return printdebug # Return Original decorator @ printdebug_level (Level = 5) # decorator's parameter, debug level set to 5def login (User): Print ('in login: '+ User) login ('jatsz ')
Let's explain the entire call process of login ('jatsz:
[Decorated] Login ('jatsz ') => printdebug_level (5) => printdebug [With closure value 5] (LOGIN) ('jatsz ') => _ decorator ('jatsz ')[Use value 5] => [Real] Login ('jatsz ')
5. Decorated functions with return values
Sometimes login returns a value. For example, a message is returned to indicate whether login is successful.
Login_result = login ('jatsz ')
We need to pass the return value between decorator and the called function:
Def printdebug (func): def _ decorator (User): Print ('Enter the login') Result = func (User) # recevie the native function call resultprint ('Exit the login') return result # Return to callerreturn _ decorator @ printdebug def login (User): Print ('in login: '+ User) MSG = "success" if user = "jatsz" else "fail" Return MSG # login with a return valueresult1 = login ('jatsz '); print result1 # print login resultresult2 = login ('candy '); print result2
Let's explain the transfer process of the returned value:
... Omit for brief... [Real] [MSG from login ('jatsz ') => [result from] _ decorator => [Assign] Result1
6. apply multiple decorators
We can apply multiple decorators to a function. In this case, we need to pay attention to the results produced by applying the order of the decorators. Impact:
Def printdebug (func): def _ decorator (): Print ('Enter the login') func () print ('Exit the login ') return _ decorator def others (func): # define a other decoratordef _ decorator (): print '*** other decorator ***' func () return _ decorator @ others # apply two of decorator @ printdebugdef login (): Print ('in login: ') @ printdebug # Switch decorator order @ othersdef logout (): print ('in logout: ') login () print (' ------------------------- ') logout ()
We defined Another decorator others, and then we applied the two decorator to the login function and the logout function respectively. The application method is very simple. In the function definition, you can simply use two. Let's take a look at the output of the above Code:
$ Python deoc. py *** other decorator *** enter the loginin login: exit the login ------------------------enter ----- the login *** other decorator *** in logout: exit the login
We can see that the two decorators have been successfully applied, but the output is different. The reason for this output is that the order of the decorator is different. Let's look at our login definition. We apply others first, and then printdebug. The opposite is true for logout functions. What happened? If you carefully read the output result of the logout function, you can see the recursion of the decorator. The output shows that the logout function first applies printdebug and prints "Enter the login ". During the _ decorator call of printdebug, others's _ decorator is applied and "*** other decorator ***" is printed ***". In fact, logically, we can look at the process of applying the logout function to the decorator as follows (pseudo code ):
@ Printdebug # Switch decorator Order (@ others (DEF logout (): Print ('in logout :')))
Let's explain the entire process of applying decorator recursively:
[Printdebug decorated] Logout () =>
Printdebug. _ decorator [Call [Others decorated] logout ()] =>
Printdebug. _ decorator. Other. _ decorator [Call real logout]
7. Flexible Use
Under what circumstances is the deprecator not applicable? The decorator cannot apply a part of a function, but can only act on the entire function.
The login function is a whole. When we want to apply decorator to some functions, the decorator cannot be started. For example, we want to apply the decorator to the following statements:
MSG = "success" if user = "jatsz" else "fail"
What should I do?
A work und is "extract functions". We extract this line of statements into functions and then decorate the extracted function application:
Def printdebug (func): def _ decorator (User): Print ('Enter the login') Result = func (User) print ('Exit the login ') return result return _ decorator def login (User): Print ('in login: '+ User) MSG = validate (User) # exact to a methodreturn MSG @ printdebug # apply the decorator for exacted methoddef validate (User ): MSG = "success" if user = "jatsz" else "fail" Return msgresult1 = login ('jatsz '); print result1
For a more practical application, sometimes validate is a time-consuming process. To improve the application performance, we will cache the result of validate for a period of time (30 seconds). With decorator and the above method, we can achieve this:
Import timedictcache ={} def cache (func): def _ decorator (User): Now = time. time () if (user in dictcache): result, cache_time = dictcache [user] If (now-cache_time)> 30: # cache expiredresult = func (User) dictcache [user] = (result, now) # cache the result by userelse: Print ('cache hits ') else: Result = func (User) dictcache [user] = (result, now) return result return _ decorator def login (User): Print ('in login: '+ User) MSG = validate (User) return MSG @ cache # apply the cache for this slow validationdef validate (User): time. sleep (5) # simulate 10 second blockmsg = "success" if user = "jatsz" else "fail" Return msgresult1 = login ('jatsz '); print result1 result2 = login ('jatsz '); print result2 # This login will return immediately by hit the cacheresult3 = login ('candy'); print result3
Reference:
Http://stackoverflow.com/questions/739654/understanding-python-decorators -- Understanding Python decorators
Http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html-Python modifier Learning (Step 9)
Http://www.python.org/dev/peps/pep-0318/ -- Pep 318 -- decorators for functions and methods