5 cases explain the decorator in detail

decorator
Decorator is a function that is often used in program development. Using decorators well can improve development efficiency, so this is also a must-ask question in Python interviews. But for many people who are new to this knowledge, this function is a bit confusing. They bypassed it directly during self-study, and then hung up when they were asked in the interview, because decorators are the basic knowledge of program development. Experts say that you know Python, read the following article to ensure that you learn decorators.

1. First understand this code
#### First wave ####
def foo():
print('foo')
foo # means it is a function
foo() # means execute foo function
#### Second Wave ####
def foo():
print('foo')
foo = lambda x: x + 1
foo() # Execute the lambda expression instead of the original foo function, because the name foo is redirected to another anonymous function
The function name is just a variable, it just points to the defined function, so it can be called through the function name (), if the function name = xxx is modified, then when the function name () is executed, it will be called I don't know the previous function

2. Demand comes
The start-up company has N business departments, and the basic platform department is responsible for providing the underlying functions, such as: database operation, redis call, monitoring API and other functions. When the business department uses the basic functions, it only needs to call the functions provided by the basic platform. as follows:

################ The functions provided by the basic platform are as follows ################
def f1():
print('f1')
def f2():
print('f2')
def f3():
print('f3')
def f4():
print('f4')
################ Business department A calls the functions provided by the basic platform #################
f1()
f2()
f3()
f4()
################ Business department B calls the functions provided by the basic platform #################
f1()
f2()
f3()
f4()
At present, the company is proceeding in an orderly manner. However, the developers of the previous basic platform did not pay attention to verification-related issues when writing code, namely:
The functions provided by the basic platform can be used by anyone. Now it is necessary to refactor all the functions of the basic platform, and add a verification mechanism to all the functions provided by the platform, that is, to perform verification before executing the function.

The elder handed over the work to Low B, and he did this:
Negotiate with each business department, each business department writes its own code, and verifies before calling the functions of the basic platform. Hey, so the basic
The platform does not require any modification. It's great, I have plenty of time to pick up girls...

Low B was fired that day...

The elder gave the job to Low BB, and here's how he did it:
################ The functions provided by the basic platform are as follows ################
def f1():
# verify 1
# verify 2
# verify 3
print('f1')
def f2():
# verify 1
# verify 2
# verify 3
print('f2')
def f3():
# verify 1
# verify 2
# verify 3
print('f3')
def f4():
# verify 1
# verify 2
# verify 3
print('f4')
################ Business department remains unchanged ################
### Business department A calls the functions provided by the basic platform ###
f1()
f2()
f3()
f4()
### Business department B calls the functions provided by the basic platform ###
f1()
f2()
f3()
f4()
After a week Low BB got fired...

The elder handed over the job to the Low BBB, and here's how he did it:
Only the code of the basic platform is refactored, and other business departments do not need to make any changes

################ The functions provided by the basic platform are as follows ################
def check_login():
# verify 1
# verify 2
# verify 3
pass
def f1():
check_login()
print('f1')
def f2():
check_login()
print('f2')
def f3():
check_login()
print('f3')
def f4():
check_login()
print('f4')
The elder looked at the realization of Low BBB, a gratified smile leaked from his mouth, and chatted with Low BBB earnestly:

Boss said:
When writing code, you must follow the principle of openness and closure. Although this principle is used for object-oriented development, it is also applicable to functional programming. Simply put
Said, it stipulates that the implemented function code is not allowed to be modified, but can be extended, namely:

Enclosure: Implemented functional code block
Open: to extension development
If the principle of openness and closure is applied to the above requirements, then it is not allowed to modify the code inside the functions f1, f2, f3, and f4. The boss gave Low BBB an implementation plan:

def w1(func):
def inner():
# verify 1
# verify 2
# verify 3
func()
return inner
@w1
def f1():
print('f1')
@w1
def f2():
print('f2')
@w1
def f3():
print('f3')
@w1
def f4():
print('f4')
For the above code, it is only necessary to modify the code of the basic platform, so that the function f1 f2 f3 f4 can be executed before other people call the function f1 f2 f3 f4
[Verification] operation, and other business departments do not need to do anything.
Low BBB asked in horror, what is the internal execution principle of this code?
The elder was about to get angry, when suddenly Low BBB's cell phone fell to the ground, and it happened that the screensaver was a photo of Low BBB's girlfriend. The elder shook his head, smiled happily, and decided to make good friends with Low BBB.
Started to explain in detail:
Take f1 alone as an example:

def w1(func):
def inner():
# verify 1
# verify 2
# verify 3
func()
return inner
@w1
def f1():
print('f1')
The python interpreter will interpret the code from top to bottom, the steps are as follows:

def w1(func): ==> load w1 function into memory
@w1
That's right, on the surface, the interpreter will only interpret these two lines of code, because the internal code of the function will not be executed until it is called.
On the surface, the interpreter will actually execute these two sentences, but there is a big article in the code of @w1, @function name is a syntactic sugar of python.

In the above example, @w1 will perform the following operations internally:
Execute the w1 function
Execute the w1 function, and use the functions below @w1 as the parameters of the w1 function, that is: @w1 is equivalent to w1(f1) So, it will go to
Execute:

def inner():
# verify 1
# verify 2
# verify 3
f1() # func is a parameter, at this time func is equal to f1
return inner# The returned inner, inner represents a function, not an execution function, in fact, it is to insert the original f1 function into another
in a function
return value of w1
Assign the return value of the executed w1 function to the function name f1 of the function below @w1, and then reassign the return value of w1 to f1, namely:

new f1 = def inner():
# verify 1
# verify 2
# verify 3
It turns out that f1()
return inner
Therefore, when the business department wants to execute the f1 function in the future, it will execute the new f1 function, first execute the verification inside the new f1 function, and then execute the original
The original f1 function, and then return the return value of the original f1 function to the business caller.

In this way, the verification function is executed, and the content of the original f1 function is executed, and the return value of 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 house to help you solve it at night! ! !

3. Discuss decorators again
# Define function: complete package data
def makeBold(fn):
def wrapped():
return "" + fn() + ""
return wrapped
# Define function: complete package data
def makeItalic(fn):
def wrapped():
return "" + fn() + ""
return wrapped
@makeBold
def test1():
return "hello world-1"
@makeItalic
def test2():
return "hello world-2"
@makeBold
@makeItalic
def test3():
return "hello world-3"
print(test1())
print(test2())
print(test3())
operation result;

hello world-1
hello world-2
hello world-3
4. Decorator function
import log
Function execution time statistics
Preparatory processing before executing the function
Clean up function after executing function
Scenarios such as permission verification
cache
5. Decorator example
Example 1: Function without parameters
def check_time(action):
def do_action():
action()
return do_action
@check_time
def go_to_bed():
print('go to sleep')
go_to_bed()
The above code understands the execution of the decorator and can be understood as

result = check_time(go_to_bed) # pass go_to_bed as a parameter to the check_time function, and define another
The variable is used to save the running result of check_time
result() # The return value of the check_time function result is a function, and result() calls this function again to make it call go_
to_bed function
Example 2: The decorated function has parameters
def check_time(action):
def do_action(a,b):
action(a,b)
return do_action
@check_time
def go_to_bed(a,b):
print('{} go to {} sleep'.format(a,b))
go_to_bed("zhangsan", "bed")
Example 3: The decorated function has variable length parameters
def test(cal):
def do_cal(*args, **kwargs):
cal(*args, **kwargs)
return do_cal
@test
def demo(*args):
sum = 0
for x in args:
sum +=x
print(sum)
demo(1, 2, 3, 4)
Example 4: return in a decorator
def test(cal):
def do_cal(*args, **kwargs):
return cal(*args,**kwargs) # You need to write a return statement here, which means calling the function and getting the return of the function
value and return
return do_cal
@test
def demo(a,b):
return a + b
print(demo(1, 2)) #3
Summarize:
In general, in order to make the decorator more general, there can be return

Example 5: Decorator with parameters
def can_play(clock):
print('The outermost function is called, clock = {}'.format(clock))
def handle_action(fn):
def do_action(name, game):
if clock < 21:
fn(name, game)
else:
print('Too late to play the game')

return do_action

return handle_action

@can_play(20) # Decorator function with parameters
def play_game(name, game):
print(name + 'playing' + game)

play_game('Zhang San', 'Glory of the King')
1. tune Use the can_play function and pass 12 to the clock
2. Then call the handle_action method and pass play_game to fn
3. Calling play_game at this time actually calls do_action

Improve: Use decorators to implement permission verification
The following codes are not required to be mastered. It is best if you can understand them. If you can write them out by yourself, that would be great!

def outer_check(base_permission):
def check_permission(action):
def do_action(my_permission):
if my_permission & base_permission:
return action(my_permission)
else:
return 'Sorry, you do not have this permission'
return do_action
return check_permission


READ_PERMISSION = 1
WRITE_PERMISSION = 2
EXECUTE_PERMISSION = 4


@outer_check(base_permission=READ_PERMISSION)
def read(my_permission):
return 'read data'

@outer_check(base_permission=WRITE_PERMISSION)
def write(my_permission):
return 'write data'

@outer_check(base_permission=EXECUTE_PERMISSION)
def execute(my_permission):
return 'execute program'

print(read(5))

Related Articles

Explore More Special Offers

  1. Short Message Service(SMS) & Mail Service

    50,000 email package starts as low as USD 1.99, 120 short messages start at only USD 1.00

phone Contact Us