彻底搞懂python 装饰器, 超详细图文解说

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/gymaisyl/article/details/83019756

首先,咱们先了解一个点:
写代码要遵循开放封闭原则

  • 封闭:已实现的功能代码块

  • 开放:对扩展开放

装饰器定义:

装饰器本身是一个函数,其作用是对已经封装的函数的功能的增加。

首先,我们先看一下这段代码:

def set_fun(func):
    def call_fun(a):
        print('call_fun')
        return func(a)
    return call_fun

# @set_fun  (此时被屏蔽了哈)
def test(x):
    print(x+10)

test(11)

**首先,python解释器在执行这段代码的时候,会发生这样的情况:

  • 在没有使用@set_fun装饰器的情况下,我们单独定义两个函数,会出现下图中的情况,在内存中创建两个空间,一个是set_fun变量指向的,另外一个是test这个变量指向的。

在这里插入图片描述

接下来,我们开始使用装饰器,首先先说明几个点;

  • @set_fun的装饰功能,在被装饰函数调用之前就已经装饰了;
  • @set_fun实现的逻辑==> test = set_fun(test) (本案例中)

也就是说,在执行test(11)这段代码之前,我们的 test = set_fun(test)这段代码已经被执行,就是test这个函数,已经被装饰了。
大家先记住这两个点,后面会做相关解释。

def set_fun(func):
    def call_fun(a):
        print('call_fun')
        return func(a)
    return call_fun

@set_fun  (此时开启装饰器功能)
def test(x):
    print(x+10)

test(11)

**现在,我们加上装饰器的功能,那么,解释器再运行这段代码的时候,会出现这样的情况:

  1. 第一行执行后,会开辟一个地址空间,这个地址由set_fun这个变量指向的;set_fun函数里面的代码现在不会运行;
  2. 在解释器走到第8行的时候,会执行这样一段代码:
 test = set_fun(test)

这段代码执行完之后的效果就是:
①:调用了set__fun(func)这个函数,把test作为实参传递给func(把test的引用传递给了func);
②:把set_fun函数的返回值 “call_fun”(call_fun函数的引用) ,返回给了test;
此时,出现图中的解释:
现在test这个变量,指向的是call_fun这个函数的引用,不指向之前的地址空间了;
func这个变量,指向的是原来test指向的地址空间,也就是现在下图中的【print(x+10)】的地址空间。

在这里插入图片描述

在set_fun()函数被调用执行之后,在内存中实际上已经被释放了,所以我们现在的图应该是这样的:(相当于创建的一个闭包,关于闭包的知识,不太理解的小伙伴,可以参考
闭包知识详解
在这里插入图片描述

**好的,我们现在的代码走到了13行,此时,开始调用test()函数了,那么大家想一想,现在应该怎么运行呢?

上面是不是说过,我们的test这个变量,目前指向的地址空间,已经不是刚开始的【print(x+10)】的地址空间了,而是call_fun指向的地址空间。

所以,我们在运行test(11)的时候,等同于运行call_func(11)了,然后,顺理成章,运行print('call_fun'), 在运行func(a)时,我们会执行print(11+10).

然后,我们看一下,实际运行时,我们的代码结果是:

call_fun
21


我们现在解释一下

  • @set_fun的装饰功能,在被装饰函数调用之前就已经装饰了。
    我们可以通过下面这段代码,来检验一下:
    此时,我们实在set_fun下面增加了print('开始装饰') 这段代码,然后,把test(11) 屏蔽,不调用
def set_fun(func):
    print('开始装饰')
    def call_fun(a):
        print('call_fun')
        return func(a)
    return call_fun


@set_fun
def test(x):
    print(x+10)


# test(11)

看一下此时的运行结果:

开始装饰

也就是说,在整段代码执行时,我们没有调用被装饰函数,只有定义了两个函数(一个时是闭包函数,一个时被装饰的函数), 其中,在代码运行到@set_fun 这一句时,我们的装饰器,已经开始对被装饰的函数进行装饰了。


装饰器的功能:

引入日志
函数执行时间统计
执行函数前预备处理
执行函数后清理功能
权限校验等场景
缓存

展开阅读全文

没有更多推荐了,返回首页