Detailed analysis of python decorator
Detailed analysis of python decorator
What Is it a decorator?
Recommended learning: Python video tutorial
Python decorators (fuctional decorators) are functions used to expand the functionality of the original function. The purpose is to When changing the original function name (or class name), add new functions to the function.
The special thing about this function is that its return value is also a function. This function is a function with the "original" function embedded in it.
Generally speaking, if we want to expand the original function code, the most direct way is to invade the code and modify it, for example:
import time def f(): print("hello") time.sleep(1) print("world")
This is our most original function, and then we try to record the total execution time of this function, then The simplest way is to change the original code:
import time def f(): start_time = time.time() print("hello") time.sleep(1) print("world") end_time = time.time() execution_time = (end_time - start_time)*1000 print("time is %d ms" %execution_time)
But in actual work, sometimes the core code cannot be changed directly, so without changing the original code, we You can define another function. (But the function needs to be executed again to take effect)
import time def deco(func): start_time = time.time() f() end_time = time.time() execution_time = (end_time - start_time)*1000 print("time is %d ms" %execution_time) def f(): print("hello") time.sleep(1) print("world") if __name__ == '__main__': deco(f) print("f.__name__ is",f.__name__) print()
Here we define a function deco, whose parameter is a function, and then embed the timing function into this function . But if you want to expand the functions of these tens of millions of functions,
means executing the deco() function ten million times, so this is not ideal! Next, we can try to use decorators to achieve it. First Take a look at the most original appearance of the decorator.
import time def deco(f): def wrapper(): start_time = time.time() f() end_time = time.time() execution_time = (end_time - start_time)*1000 print("time is %d ms" %execution_time ) return wrapper @deco def f(): print("hello") time.sleep(1) print("world") if __name__ == '__main__': f()
The deco function here is the most original decorator. Its parameter is a function, and the return value is also a function.
The function f() as a parameter is executed inside the return function wrapper(). Then add @deco in front of the function f(),
f() function is equivalent to being injected With the timing function, now as long as f() is called, it has been transformed into a "new function with more functions",
(no need to repeat the original function).
Extension 1: Decorator with fixed parameters
import time def deco(f): def wrapper(a,b): start_time = time.time() f(a,b) end_time = time.time() execution_time = (end_time - start_time)*1000 print("time is %d ms" % execution_time) return wrapper @deco def f(a,b): print("be on") time.sleep(1) print("result is %d" %(a+b)) if __name__ == '__main__': f(3,4)
Extension 2: Decorator without fixed parameters
import time def deco(f): def wrapper(*args, **kwargs): start_time = time.time() f(*args, **kwargs) end_time = time.time() execution_time_ = (end_time - start_time)*1000 print("time is %d ms" %execution_time) return wrapper @deco def f(a,b): print("be on") time.sleep(1) print("result is %d" %(a+b)) @deco def f2(a,b,c): print("be on") time.sleep(1) print("result is %d" %(a+b+c)) if __name__ == '__main__': f2(3,4,5) f(3,4)
Extension 3: Use multiple decorators to decorate a function
import time def deco01(f): def wrapper(*args, **kwargs): print("this is deco01") start_time = time.time() f(*args, **kwargs) end_time = time.time() execution_time = (end_time - start_time)*1000 print("time is %d ms" % execution_time) print("deco01 end here") return wrapper def deco02(f): def wrapper(*args, **kwargs): print("this is deco02") f(*args, **kwargs) print("deco02 end here") return wrapper @deco01 @deco02 def f(a,b): print("be on") time.sleep(1) print("result is %d" %(a+b)) if __name__ == '__main__': f(3,4)
''' this is deco01 this is deco02 hello,here is a func for add : result is 7 deco02 end here time is 1003 ms deco01 end here '''
Decorator calling order
Decorators can be used superimposed, so what is the order of the code after using the decorator?
For the "@" syntax in Python Sugar, the order in which the decorators are called is the reverse of the order declared using the @ syntax sugar.
In this example, "f(3, 4) = deco01(deco02(f(3, 4)))".
Python built-in decorators
There are three built-in decorators in Python, all related to classes: staticmethod, classmethod and property .
staticmethod is a class static method. Its difference from the member method is that it has no self parameter and can be called without instantiating the class.
The difference between classmethod and member method is that The first parameter received is not self (a pointer to a class instance), but cls (the specific type of the current class)
property means property, indicating information that can be directly accessed through a class instance
I won’t introduce staticmethod and classmethod here. Let’s take a look at property through an example.
Note that for Python new-style classes, if the member function decorated by the "@var.setter" decorator above is removed, Foo. The var attribute is a read-only attribute, and an exception will be thrown when assigning a value using "foo.var = 'var 2′". However, for Python classic class, the declared attributes are not read-only, so even if the "@var.setter" decorator is removed, no error will be reported.
Summary
This article introduces some uses of Python decorators. The code of the decorator is relatively easy to understand. It is easy to understand as long as you practice it through some examples.
The above is the detailed content of Detailed explanation of python decorators. For more information, please follow other related articles on the PHP Chinese website!