A decorator
Decorators are one of the most common features in Python development, and they can be very productive, so this is a must-ask question for Python interviews. Decorators are an important part of Python. In short: A decorator in Python is a function that extends the functionality of an original function.
Review function references
#### First wave ####
def func() :
print("func() called")
func # means it's a function
func() # indicates that the func function is executed
#### Second wave ####
def func() :
print("func() called")
func = lambda x: x + 1
func() # execute lambda expressions instead of func functions, since the name func is redirected to another anonymous function
Copy the code
If the function name = XXX is changed, then when the function name () is executed, the previous function will not be called.
Lambda expressions, again, are anonymous functions. The following figure can be seen
A short story will take you to understand the function of the decorator
Startups have N business units, and the basic platform department is responsible for providing low-level functions, such as database operations, Redis calls, monitoring apis, and so on. When the business uses the underlying functionality, it simply invokes the functionality provided by the underlying platform. As follows:
############### The basic platform provides the following functions: ###############
def f1() :
print('f1')
def f2() :
print('f2')
def f3() :
print('f3')
def f4() :
print('f4')
############### Service department A invokes functions provided by the basic platform ###############
f1()
f2()
f3()
f4()
############### Service department B invokes the functions provided by the basic platform ###############
f1()
f2()
f3()
f4()
Copy the code
The company is well on its way, but developers of the underlying platform didn’t focus on verifying that the functionality provided by the underlying platform could be used by anyone when they wrote code. Now you need to refactor all the functionality of the base platform and add a validation mechanism for all the functionality provided by the platform, that is, verify the functionality before it is implemented.
The boss gives the job to Low B, and here’s what he does:
Negotiate with each line of business to write their own code and validate before invoking the underlying platform functionality. Well, that doesn’t require any changes to the base platform. That’s great. Plenty of time to get laid…
Low B was fired that day…
The boss gave the job to Low BB, and here’s what he did:
############### The basic platform provides the following functions: ###############
def f1() :
Verify the # 1
Validation # 2
Validation # 3
print('f1')
def f2() :
Verify the # 1
Validation # 2
Validation # 3
print('f2')
def f3() :
Verify the # 1
Validation # 2
Validation # 3
print('f3')
def f4() :
Verify the # 1
Validation # 2
Validation # 3
print('f4')
############### The business department remains unchanged ###############
Business department A invokes the functionality provided by the underlying platform ###
f1()
f2()
f3()
f4()
Business department B calls the functionality provided by the underlying platform ###
f1()
f2()
f3()
f4()
Copy the code
A week later Low BB was fired…
The boss gave the job to Low BBB, and here’s what he did:
Only the code for the underlying platform is refactored and no changes are required for other business units
############### The basic platform provides the following functions: ###############
Add a validation function
def check() :
Verify the # 1
Validation # 2
Validation # 3
pass
def f1() :
check()
print('f1')
def f2() :
check()
print('f2')
def f3() :
check()
print('f3')
def f4() :
check()
print('f4')
Copy the code
The boss looked at the realization of Low BBB, the corners of his mouth leaked a gleam of joy, and he talked with Low BBB earnestly:
The boss said:
Writing code should follow the open and closed principle. Although this principle is used for object-oriented development, it also applies to functional programming. In simple terms, it stipulates that the implemented function code cannot be modified, but can be extended, namely:
- Closed: an implemented block of functional code
- Open: Development for extensions
If the open closed principle is applied to the above requirement, then it is not allowed to modify the code inside the functions f1, F2, F3, f4, so the boss gives Low BBB a solution:
This is the closure application, but the func passed in is a reference to the function
def check(func) :
def inner() :
Verify the # 1
Validation # 2
Validation # 3
func()
return inner
@check
def f1() :
print('f1')
@check
def f2() :
print('f2')
@check
def f3() :
print('f3')
@check
def f4() :
print('f4')
Copy the code
The above code, which is also only modified in the base platform code, can be verified before others call the functions F1, F2, F3, f4, and other business departments do not need to do anything.
Low BBB was horrified to ask, what is the internal execution principle of this code?
Boss was about to get angry, suddenly Low BBB’s phone fell to the ground, happened to be Low BBB’s girlfriend screensaver photo, boss a look at a tight shake, happy face, decided to make a good friend with Low BBB.
Detailed start to explain:
Take F1 () as an example alone:
def check(func) :
def inner() :
Verify the # 1
Validation # 2
Validation # 3
func()
return inner
@check
def f1() :
print('f1')
Copy the code
The Python interpreter interprets the code from top to bottom as follows:
- Def check(func): ==> load the check function into memory
- @check
Yes, on the face of it, the interpreter only interprets these two lines of code, because the function’s internal code is not executed until it is called.
On the face of it, the interpreter does execute these two statements, but the @check code is a big deal. The @function name is a syntactic sugar in Python.
In the previous example, @check performs the following operations internally:
Execute check
Execute the check function and take the function below @check as an argument to the check function
That is, @check is equivalent to check(f1), so it is executed internally:
def inner() :
Verify the # 1
Validation # 2
Validation # 3
func() # func is the argument, in which case func equals f1
return inner
Copy the code
Return inner, inner stands for function, non-executing function, in fact, the original f1 function is inserted into another function
The return value of the check function
F1: check (); f1: check ();
The new f1 =def inner() :
Verify the # 1
Validation # 2
Validation # 3The original f1 ()return inner
Copy the code
So, in the future, when the business wants to execute the F1 function, the new F1 function is executed, validation is performed inside the new F1 function, then the original F1 function is executed, and the return value of the original F1 function is returned to the business caller.
In this way, the validation function is performed, and the contents of the original F1 function are executed, and the value returned by the original F1 function is returned to the business caller
Low BBB do you understand? If you don’t understand, I will go to your home to help you solve it!!
This vivid little story is quoted from the Internet.
Python decorator simple application
Python’s decorator syntax begins with @, followed by the name of the decorator function, and optional arguments.
Immediately following the decorator declaration are the decorated function and the optional arguments for the decorated function, as follows:
@decorator(Optional arguments for decorators)
def func(Function parameters) :.Copy the code
Calculate the running time of the function
A + b + c = 1000 and a*a + b*b = c* C
For example, (0, 500, 500) and (500, 0, 500) can occur only one.
""" Python Key Knowledge decorator """
import time
print("# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- running time calculation function -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #")
def calc_time(func) :
Compute the running time of the function
def calc() :
Record the start time before the function call
start_time = time.time()
func()
The function ends and calculates the running time
use_time = time.time() - start_time
print(func.__name__, "use time {} seconds".format(use_time))
return calc
@calc_time
def fun1() :
[0, 1000] a + b + c = 1000, a*a + b*b = c*c
ret_set = set(a)for i in range(0.1001) :for j in range(0.1001) :for m in range(0.1001) :if (i + j + m) == 1000 and (i*i + j*j) == m*m:
# print(i, j, m)
li = [i, j, m]
Remember to sort before adding to the collection
# Prevent [0, 500, 500], [500, 0, 500], etc
li.sort()
ret_set.add(tuple(li))
print(ret_set)
@calc_time
def fun2() :
""" Improved version ""
ret_set = set(a)for i in range(10001) :for j in range(1001 - i):
m = 1000 - i - j
if i*i + j*j == m*m:
# print(i, j, m)
li = [i, j, m]
li.sort()
ret_set.add(tuple(li))
print(ret_set)
def main() :
fun1()
print()
fun2()
if __name__ == '__main__':
main()
Copy the code
The results
# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- running time calculation function -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #
{(0.500.500), (200.375.425)}
fun1 use time 99.87939643859863 seconds
{(0.500.500), (200.375.425)}
fun2 use time 0.12499618530273438 seconds
Copy the code
This section of the program not only illustrates the decoration of the powerful, reusable high, but also remind us to design a good program, program performance double.
The source code
The source code has been uploaded to Gitee PythonKnowledge: PythonKnowledge Repository.
✍ code word is not easy, the long journey always feeling, praise again go line, also hope you heroes support ❤️
The public,
Create a new folder X
Nature took tens of billions of years to create our real world, while programmers took hundreds of years to create a completely different virtual world. We knock out brick by brick with a keyboard and build everything with our brains. People see 1000 as authority. We defend 1024. We are not keyboard warriors, we are just extraordinary builders of ordinary world.