Python decorators are one of the most frequently asked questions in the interview process. Decorators are also a very useful feature. Mastering them will give you a wider range of programming ideas and make your programs more Pythonic.
Today, we will take you to understand the decoration with the recent World Cup.
The German tanks
June 17 Germany against Mexico, although xiao Chi is a fake fan, but the annual World Cup or will understand. Germany, the reigning champion, is the favorite this time. Deutschland has not lost in the group stage in 32 years! Oh, my gosh! Although little crazy rarely bet on football, but this time Germany is so strong, must win. Fight a bike to become a motorcycle! Then he bought the German team to win. In the mind think this affirmation steady! Win the club model! Small crazy even don’t look at the game, deliciously knocking code.
Then the game turned out to be a surprise 1-0 loss to Mexico, Germany lost the game, the little crazy also went to work. But the rooftop is a little crowded at this time, and the wind is big.
Small chi tearfully wrote the following code:
def guess_win(func):
def rooftop_status():
result = func()
print('The roof is full, please line up! ')
return result
return rooftop_status
@guess_win
def german_team():
print('Germany will win! ')
Copy the code
Output result:
Germany will win! The roof is full, please line up!Copy the code
What is a decorator
Decorators are, strictly speaking, just syntax candy. Decorators are callable objects that can be called just like regular callable objects, except that the argument to a decorator is a function.
Decorators exist for two scenarios, one for enhancing the behavior of the decorator function and the other for code reuse.
For example, in the example above, when we win against Germany, the original german_team() function only output Germany will win, but after using the decoration (guess_win), it has a new function: output “the roof is full, please queue up!” . This is a simple decorator that “enhances the behavior of the decorator function.”
A good decorator must follow two principles:
-
The code of the decorated function cannot be modified
-
You cannot modify the way decorated functions are called
It’s not hard to understand that in today’s production environment, a lot of code cannot be easily rewritten because of the potential for unintended effects. The other thing is that we’re looking at God’s code and we don’t know how to rewrite it. And you can’t change the call because you don’t know how many times this function is used in a project.
Decorators understand the basics
There are two things you need to know about decorators if you want to understand them well.
-
Function names can be assigned to variables
-
2 higher order functions
Function names can be assigned to variables
Let’s look at this example:
def func(name):
print('I am {}! Panic! '.format(name))
func('messi')
y = func
y('low')
Copy the code
Output result:
I'm Messi! Panic! I'm Loew! Panic!Copy the code
In the code we first define the function func, call the func function, and assign func to y. Y = func indicates that function names can be assigned to variables without affecting the call.
Some of you may not understand this. So let’s compare this to what we usually do. This is the same as integers and numbers, and you’ll be familiar with the following code:
a = 1
b = a
print(a, b)
Copy the code
2 higher order functions
Higher-order functions meet either of the following two conditions: a. Can accept function names as arguments; B. The return value can contain the function name.
Functions such as map and filter in the Python standard library are higher-order functions.
l = [1, 2, 4]
r = map(lambda x: x*3, l)
for i in r:
print('Current rooftop number:', i)
Copy the code
Output result:
Number of current rooftop personnel: 3 Number of current rooftop personnel: 6 Number of current rooftop personnel: 12Copy the code
A custom function that returns a function, also a higher-order function:
def f(l):
return map(lambda x: x *5, l)
a = f(l)
for i in a:
print('Current rooftop number:', i)
Copy the code
Output result:
Number of current rooftop personnel: 5 Number of current rooftop personnel: 10 Number of current rooftop personnel: 20Copy the code
Implement a similar decorator
Now that you know about “function name assignment” and “higher-order functions,” we can try to implement a similar decorator with these two foundations.
def status(func):
print('What a panic! ')
return func
def name():
print('I'm Messi! ')
temp = status(name)
temp()
Copy the code
Output result:
Panic! I'm Messi!Copy the code
In this example we define a status function that takes a function name and returns it directly. This satisfies the need to leave the original function name unchanged and add a new function. But there is a drawback here that the way the function is called has changed. That is, temp is not the original name.
Temp = status(name) temp = status(name) temp = status(name) temp = status(name) New functionality is added without changing the original function or how it is called. The modified code is as follows:
def status(func):
print('What a panic! ')
return func
def name():
print('I'm Messi! ')
name = status(name)
name()
Copy the code
The downside of such code is that every time we use such a decorator, we have to write something like name = status(name). Programmers are lazy, which is why there are so many advanced grammars. To simplify this situation, Python provides a syntax sugar @, which is used above each decorated function to dispense with the line name = status(name), resulting in the following code:
def status(func):
print('What a panic! ')
return func
@status
def name():
print('I'm Messi! ')
name()
Copy the code
So we know how the decorator works:
-
1 Write a higher-order function that takes a function and returns a function.
-
2. Use the syntax sugar @ to simplify the assignment operation.
But there’s something different about the first example. In our initial example, we also implemented a rooftop_status function to determine if the roof is currently full. But now we return the function name directly, so we can’t do anything after the function is called. Messi and Germany panic, we panic, each want to see the rooftop, but before that we also have to consider the rooftop situation.
In order to judge the situation of the roof, we need to nest a layer of functions at this time, write the part that realizes the extra function in the inner layer function, and then return the inner layer function. This is why decorators are nested functions.
In addition, the first example has no return value and no arguments, which would require further refinement to decorate functions that have both arguments and return values. Decorators capable of handling return values:
def guess_win(func):
def rooftop_status():
result = func()
print('The roof is full, please line up! ')
return result
return rooftop_status
@guess_win
def german_team():
print('Germany will win! ')
return 'Won the club model! Lose the sea work! '
x = german_team()
print(x)
Copy the code
Output result:
Germany will win! The roof is full, please line up! Win the club model! Lose the sea work!Copy the code
Decorators that can handle arguments:
def guess_win(func):
def rooftop_status(*args, **kwargs):
result = func(*args, **kwargs)
print('The roof is full, please line up! ')
return result
return rooftop_status
@guess_win
def german_team(arg):
print('{} win! '.format(arg))
return 'Won the club model! Lose the sea work! '
x = german_team('Germany')
y = german_team('Spain')
print(x)
Copy the code
Output result:
Germany will win! The roof is full, please line up! Spain will win! The roof is full, please line up! Win the club model! Lose the sea work!Copy the code
conclusion
A decorator is essentially a function whose argument is another function (the function being decorated). Decorators typically process the decorated function extra, then return it or replace it with another function or callable. Well-behaved decorators can be reused to reduce code.
For this World Cup, I summed up the next.
This is the latest python tutorial for 2018.