Original link: https://www.kingname.info/2023/04/16/order-of-decorator/
When it comes to the execution order of Python decorators, there are a lot of half-baked ones:
The decorators near the function name are executed first, and the decorators far away from the function name are executed after.
This statement is not accurate. But most of these half-assed people will still be dissatisfied. They will throw out a piece of code to you to “prove” their point of view:
1 |
def decorator_outer ( func ): |
The running effect is shown in the figure below:
The decorator_inner
is close to the function name, it is an inner decorator, and print
inside it is printed out first; decorator_outer
is far away from the function name, it is an outer decorator, and print
inside it is printed out later. It seems that内层装饰器先执行,外层装饰器后执行
.
Why do I say this view is inaccurate? Let’s take a look at the following code:
1 |
def decorator_outer ( func ): |
The running effect of the above code is shown in the following figure:
As can be seen from the figure, in the code inside the decorator, the code outside wrapper
closure is indeed executed first by the inner decorator and after the outer decorator. But the code inside the closure wrapper
is a little more complicated:
- The outer decorator is executed first, but only part of it is executed until
func()
is called - The inner decorator starts executing
- The inner decorator is executed
- The outer decorator is executed
The execution effect is somewhat similar to:
1 |
def func (): |
The running effect is shown in the figure below, which is consistent with the running order of each wrapper
closure in the decorator.
Therefore, when we say that when multiple decorators are stacked, which decorator’s code runs first, we cannot say that the code of the inner decorator runs first. This will give people the illusion that the code of the inner decorator is run first from the first line to the last line. The accurate statement should be that the code outside wrapper
is indeed run first by the inner decorator, and then by the outer decorator. But the code inside wrapper
is that the outer decorator先开始运行,后运行完毕
, and the inner decorator后开始运行,先运行完毕
.
This knowledge seems a bit like interview stereotypes, what’s the use? Let me give you an example. The following is an interface written using FastAPI:
1 |
from fastapi import FastAPI |
The user accesses this interface, and the parameter dataset_id
is passed in the URL to obtain the information of the dataset. As shown below:
Now, to add permission verification, first determine whether the user is logged in or not. In the case that the user has logged in, check whether the user has the permission of this data set. Data set information can only be returned when there is permission for this data set.
You must have thought of using a decorator to do these two steps. The code you wrote at the beginning might look like this:
1 |
def check_login ( func ): |
At this time, we need to ensure that the code in check_login
to check whether the user is logged in runs first. Then it can be the code to check the permission of the data set in check_data_set_permission
.
The half-bad guy at the beginning of this article thinks that the decorator close to the function name is executed first, and the decorator far away from the function name is executed after. According to their theory, it would be written as:
1 |
@check_data_set_permission |
It is obviously wrong to write this way. Because check_data_set_permission
decorator has a premise that the user has logged in, the code will come here. Then he will go directly to the session to get the user ID. A user who is not logged in does not have a user ID. There will be an error in this step of taking the ID.
According to the explanation above in this article, since these two logics are inside wrapper
.
For the code inside wrapper
, the outer decorator starts running first. Therefore, the correct order of our decorators here can only be arranged in the following order:
1 |
@check_login |
This way of writing, intuitively, will contradict the cognition at the beginning of this article. But that’s the correct order.
This article is transferred from: https://www.kingname.info/2023/04/16/order-of-decorator/
This site is only for collection, and the copyright belongs to the original author.