


Detailed explanation of Python decorators from shallow to deep
The function of decorator is available in many languages, and the names are also different. In fact, it embodies a design pattern that emphasizes the open and closed principle. It is more used for later function upgrades rather than writing new ones. code. Decorators can not only decorate functions, but also decorate other objects, such as classes, but usually, we use decorated functions as an example to introduce their usage. To understand how decorators work in Python, you need to go step by step. This article tries to be as simple and easy to understand as possible, starting from the most basic content.
(Note: The following uses the Python3.5.1 environment)
1. Function-related basics of Python
First, it must be emphasized that python is executed sequentially from top to bottom , and when encountering the function's definition code block, it will not be executed immediately. Only when the function is called will the internal code block be executed.
1 2 3 4 |
|
Look again, the example of sequential execution:
1 2 3 4 5 6 7 |
|
It can be seen that due to the sequential execution, the following foo overwrites the above foo. Therefore, there are requirements for the placement of code in Python and cannot be placed arbitrarily. The function body must be placed before the called statement.
Secondly, we need to figure out a few things first: function name, function body, return value, memory address of the function, function name plus parentheses, function name plus parentheses are treated as parameters, function name plus parentheses are treated as As parameters, return function name, return function name plus parentheses. For the following function:
1 2 3 4 |
|
Function name: foo
Function body: Lines 1-3
Return value: String "ok" If not given explicitly return object, then None is returned by default. Is the location where the function body is saved in memory.
Add parentheses to the function name: For example, foo(), the calling method of the function. As long as this parentheses are seen, the program will find the function body from the memory based on the function name, and then execute it
1 2 3 4 5 6 7 8 |
|
In python, everything is an object, and functions are no exception. Therefore, you can use the function name, or even the function name with parentheses to call it, as the return value of another function. In the above code, outer and foo are two functions. outer(foo) means passing the function name of foo function as a parameter to outer function and executing outer function; outer(foo()) means treating the return value after execution of foo function as The parameters are passed to the outer function and the outer function is executed. Since the foo function does not specify a return value, it actually passes a None to the outer function. Pay attention to the difference. Whether there are parentheses or not is the key!
Similarly, inside the outer function, an inner is returned, which is a function defined inside the outer function. Note that since there are no parentheses after inner, the function body of inner is returned, which is actually the function body of inner. It's just the name inner, a simple reference. So, what if the outer function returns inner()? You should be very clear by now, it will first execute the content of the inner function, and then return None to outer, and outer will return None to the object that called it.
Please remember that the function name, function plus parentheses can be passed as parameters, or can be returned as the return value. The presence or absence of parentheses has two completely different meanings!
2. Usage scenarios of decorators
Decorators are usually used to add additional functions to the original function code and functionality without changing it. For example, execute something before the original function is executed, and execute something after execution.
Let us take an example to see the usage scenarios of decorators and the design patterns they embody. (I'm sorry that I can't design a better scenario, so I can only cite Wu Dashen's case to deduce it)
There is a large company, and its basic platform department is responsible for the development of internal applications and APIs. Hundreds of business departments are responsible for different businesses, and they each call different functions provided by the basic platform department to handle their own business. The situation is as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Since the company was in the early stages of entrepreneurship, when the basic platform department developed these functions, due to various For various reasons, such as time, lack of consideration, etc., security authentication is not performed for function calls. Now, the director of the platform department decided to make up for this flaw, so:
The first time, the director called an operation and maintenance engineer, and the engineer ran up and down to notify departments one by one, asking them to add authentication functions to the code. However, he was fired that day.
第二回:主管又叫来了一个运维工程师,工程师用shell写了个复杂的脚本,勉强实现了功能。但他很快就回去接着做运维了,不会开发的运维不是好运维....
第三回:主管叫来了一个python自动化开发工程师,哥们是这么干的:只对基础平台的代码进行重构,让N个业务部门无需做任何修改。这哥们很快也被开了,连运维也没得做。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
第四回:主管又换了个 工程师,他是这么干的:定义个认证函数,原来其他的函数调用它,代码如下框。但是,主管依然不满意,不过这一次他解释了为什么。主管说:写代码要遵循开放封闭原则,虽然在这个原则主要是针对面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现的功能代码内部不允许被修改,但外部可以被扩展,即:封闭:已实现的功能代码块;开放:对扩展开放。如果将开放封闭原则应用在上述需求中,那么就不允许在函数 f1 、f2、f3......f100的内部进行代码修改。遗憾的是,工程师没有漂亮的女朋友,所以很快也被开除了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
第五回:已经没有时间让主管找别人来干这活了,他决定亲自上阵,并且打算在函数执行后再增加个日志功能。主管是这么想的:不会装饰器的主管不是好码农!要不为啥我能当主管,你只能被管呢?嘿嘿。他的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
对于上述代码,也是仅需对基础平台的代码进行拓展,就可以实现在其他部门调用函数 f1 f2 f3 f100 之前都进行认证操作,在操作结束后保存日志,并且其他业务部门无需他们自己的代码做任何修改,调用方式也不用变。“主管”写完代码后,觉得独乐了不如众乐乐,打算显摆一下,于是写了篇博客将过程进行了详细的说明。
三、装饰器的内部原理、
下面我们以f1函数为例进行说明:
1 2 3 4 5 6 7 8 9 10 |
|
运用我们在第一部分介绍的知识来分析一下上面这段代码:
程序开始运行,从上往下编译,读到def outer(func):的时候,发现这是个“一等公民”->函数,于是把函数体加载到内存里,然后过。
读到@outer的时候,程序被@这个语法糖吸引住了,知道这是个装饰器,按规矩要立即执行的,于是程序开始运行@后面那个名字outer所定义的函数。(相信没有人会愚蠢的将@outer写到别的位置,它只能放在被装饰的函数的上方最近处,不要空行。)
程序返回到outer函数,开始执行装饰器的语法规则,这部分规则是定死的,是python的“法律”,不要问为什么。规则是:被装饰的函数的名字会被当作参数传递给装饰函数。装饰函数执行它自己内部的代码后,会将它的返回值赋值给被装饰的函数。
如下图所示:
这里面需要注意的是:
@outer和@outer()有区别,没有括号时,outer函数依然会被执行,这和传统的用括号才能调用函数不同,需要特别注意!那么有括号呢?那是装饰器的高级用法了,以后会介绍。
是f1这个函数名(而不是f1()这样被调用后)当做参数传递给装饰函数outer,也就是:func = f1,@outer等于outer(f1),实际上传递了f1的函数体,而不是执行f1后的返回值。
outer函数return的是inner这个函数名,而不是inner()这样被调用后的返回值。
如果你对第一部分函数的基础知识有清晰的了解,那么上面的内容你应该很容易理解。
4. 程序开始执行outer函数内部的内容,一开始它又碰到了一个函数,很绕是吧?当然,你可以在 inner函数前后安排点别的代码,但它们不是重点,而且有点小麻烦,下面会解释。inner函数定义块被程序观察到后不会立刻执行,而是读入内存中(这是潜规则)。
5. 再往下,碰到return inner,返回值是个函数名,并且这个函数名会被赋值给f1这个被装饰的函数,也就是f1 = inner。根据前面的知识,我们知道,此时f1函数被新的函数inner覆盖了(实际上是f1这个函数名更改成指向inner这个函数名指向的函数体内存地址,f1不再指向它原来的函数体的内存地址),再往后调用f1的时候将执行inner函数内的代码,而不是先前的函数体。那么先前的函数体去哪了?还记得我们将f1当做参数传递给func这个形参么?func这个变量保存了老的函数在内存中的地址,通过它就可以执行 老的函数体,你能在inner函数里看到result = func()这句代码,它就是这么干的!
6.接下来,还没有结束。当业务部门,依然通过f1()的方式调用f1函数时,执行的就不再是老的f1函数的代码,而是inner函数的代码。在本例中,它首先会打印个“认证成功”的提示,很显然你可以换成任意的代码,这只是个示例;然后,它会执行func函数并将返回值赋值个变量result,这个func函数就是老的f1函数;接着,它又打印了“日志保存”的提示,这也只是个示例,可以换成任何你想要的;最后返回result这个变量。我们在业务部门的代码上可以用 r = f1()的方式接受result的值。
7.以上流程走完后,你应该看出来了,在没有对业务部门的代码和接口调用方式做任何修改的同时,也没有对基础平台部原有的代码做内部修改,仅仅是添加了一个装饰函数,就实现了我们的需求,在函数调用前先认证,调用后写入日志。这就是装饰器的最大作用。
问题:那么为什么我们要搞一个outer函数一个inner函数这么复杂呢?一层函数不行吗?
答:请注意,@outer这句代码在程序执行到这里的时候就会自动执行outer函数内部的代码,如果不封装一下,在业务部门还未进行调用的时候,就执行了些什么,这和初衷有点不符。当然,如果你对这个有需求也不是不行。请看下面的例子,它只有一层函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
看到没?我只是定义好了函数,业务部门还没有调用f1函数呢,程序就把工作全做了。这就是封装一层函数的原因。
四、装饰器的参数传递
细心的朋友可能已经发现了,上面的例子中,f1函数没有参数,在实际情况中肯定会需要参数的,那参数怎么传递的呢?
一个参数的情况:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
在inner函数的定义部分也加上一个参数,调用func函数的时候传递这个参数,很好理解吧?可问题又来了,那么另外一个部门调用的f2有2个参数呢?f3有3个参数呢?你怎么传递?
很简单,我们有*args和**kwargs嘛!号称“万能参数”!简单修改一下上面的代码:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
五、更进一步的思考
一个函数可以被多个函数装饰吗?可以的!看下面的例子!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
更进一步的,装饰器自己可以有参数吗?可以的!看下面的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
|
又绕晕了?其实你可以这么理解,先执行Filter函数,获得它的返回值outer,再执行@outer装饰器语法。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持PHP中文网!
更多Detailed explanation of Python decorators from shallow to deep相关文章请关注PHP中文网!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

Python is suitable for data science, web development and automation tasks, while C is suitable for system programming, game development and embedded systems. Python is known for its simplicity and powerful ecosystem, while C is known for its high performance and underlying control capabilities.

You can learn the basics of Python within two hours. 1. Learn variables and data types, 2. Master control structures such as if statements and loops, 3. Understand the definition and use of functions. These will help you start writing simple Python programs.

Python excels in gaming and GUI development. 1) Game development uses Pygame, providing drawing, audio and other functions, which are suitable for creating 2D games. 2) GUI development can choose Tkinter or PyQt. Tkinter is simple and easy to use, PyQt has rich functions and is suitable for professional development.

You can learn basic programming concepts and skills of Python within 2 hours. 1. Learn variables and data types, 2. Master control flow (conditional statements and loops), 3. Understand the definition and use of functions, 4. Quickly get started with Python programming through simple examples and code snippets.

Python is widely used in the fields of web development, data science, machine learning, automation and scripting. 1) In web development, Django and Flask frameworks simplify the development process. 2) In the fields of data science and machine learning, NumPy, Pandas, Scikit-learn and TensorFlow libraries provide strong support. 3) In terms of automation and scripting, Python is suitable for tasks such as automated testing and system management.

Python is easier to learn and use, while C is more powerful but complex. 1. Python syntax is concise and suitable for beginners. Dynamic typing and automatic memory management make it easy to use, but may cause runtime errors. 2.C provides low-level control and advanced features, suitable for high-performance applications, but has a high learning threshold and requires manual memory and type safety management.

To maximize the efficiency of learning Python in a limited time, you can use Python's datetime, time, and schedule modules. 1. The datetime module is used to record and plan learning time. 2. The time module helps to set study and rest time. 3. The schedule module automatically arranges weekly learning tasks.

Python excels in automation, scripting, and task management. 1) Automation: File backup is realized through standard libraries such as os and shutil. 2) Script writing: Use the psutil library to monitor system resources. 3) Task management: Use the schedule library to schedule tasks. Python's ease of use and rich library support makes it the preferred tool in these areas.
