Python装饰器笔记

Python中的装饰器是基于闭包的基础上的,作用是拓展原来函数功能的一种函数。

什么是闭包呢?

闭包可以简单理解为就是一个嵌套函数,一个外函数和一个内函数并且外函数的返回值是内函数对象。

一个简单的装饰器如下:

def demo(fun):
    def inner_func():
        print("开始装饰")
        fun()
        print("装饰完毕")
    return inner_func


@demo    # 装饰器装饰func函数
def func():
    print("hello word")


if __name__ == '__main__':
    func()


"""
输出结果===》

开始装饰
hello word
装饰完毕

"""

带参数的装饰器:

def demo(fun):
    def inner_func(a, b):
        print("开始装饰")
        fun(a, b)
        print("装饰完毕")
    return inner_func


@demo
def func(a, b):
    result = a + b
    print(result)


if __name__ == '__main__':
    func(10, 100)

"""
输出结果===》

开始装饰
110
装饰完毕

"""

注意: 当函数带有参数时,而装饰器不带参数会报错。

在装饰器中,外函数传函数对象,内函数传函数对象的参数。

对于不定长参数的传值可以改为如下示例:

def demo(fun):
    def inner_func(*args, **kwargs):
        print("开始装饰")
        fun(*args, **kwargs)
        print("装饰完毕")
    return inner_func


@demo
def func(a, b, c):
    result = a + b + c
    print(result)


if __name__ == '__main__':
    func(10, 100, 503)

"""
输出结果===》

开始装饰
613
装饰完毕

"""

对于有多个装饰器的情况:

def demo1(fun):
    print("我是demo1")

    def inner_func(*args, **kwargs):
        print("demo1开始装饰")
        fun(*args, **kwargs)
        print("demo1装饰完毕")

    return inner_func


def demo2(fun):
    print("我是demo2")

    def inner_func2(*args, **kwargs):
        print("demo2开始装饰")
        fun(*args, **kwargs)
        print("demo2装饰完毕")

    return inner_func2


@demo1
@demo2
def func(a, b, c):
    result = a + b + c
    print(result)


if __name__ == '__main__':
    func(10, 100, 503)

"""
输出结果===》

我是demo2
我是demo1
demo1开始装饰
demo2开始装饰
613
demo2装饰完毕
demo1装饰完毕

"""

看这个输出结果是不是有点难以理解?

在有多个装饰器的时候,先自底向上执行装饰器的定义,而后自顶向下执行装饰器的功能。

用堆栈来理解一下,我们知道栈都是(先入后出,后入先出)先自底向上执行装饰器的定义,就是入栈,自顶向下执行装饰器,就是出栈的过程。

我们再来详细分析一下,demo2先装饰func,然后demo1装饰demo2的返回结果,即

test = demo2(fun)
demo1(test)

函数的执行由内向外执行,即先执行括号内的代码块,

demo2(fun)    # 执行demo2(fun)

"""
先执行demo2函数内的语句块,即执行print("我是demo2"),
输出: 我是demo2
往下走遇到函数,在Python中,函数是不会自己执行的,除非是有其他语句块调用他,
所以继续往下走,遇到return返回,返回值为demo2的内函数,此时demo2(fun)执行完毕

"""

接下来执行demo1(test)

demo1(test)     # 执行demo1(test), 此时的test为demo2的返回值,即demo2的内函数inner_fun2

"""

执行demo1内的代码语句, print("我是demo1")
输出===> 我是demo1

接着往下走遇到函数定义,函数不会自动执行,继续往下走,碰到了return语句,返回值为inner_func

"""

上面执行完之后变成了这样inner_func(test)

inner_func(test)  # 执行

"""

执行inner_func函数的代码语句-> print("demo1开始装饰")
输出结果===> demo1开始装饰

往下走遇到了函数调用语句-> fun()   此时的fun则指向test,而test指向 demo2的内函数inner_func2

所以fun() 就是 inner_func2()
进入inner_func2执行里面的代码语句-> print("demo2开始装饰")
输出结果===> demo2开始装饰

往下走又遇上了函数调用语句-> fun(), 此时的fun()则指向 func()被装饰的函数对象
执行func函数的代码语句-> result = a + b + c, 将计算出的值,赋值给result变量
再往下执行-> print(result)  输出语句
输出结果===> 613
func函数执行完毕返回函数调用处
往下走执行-> print("demo2装饰完毕")
输出结果===> demo2装饰完毕
inner_func2()函数执行完毕,返回上一层函数调用处

执行语句-> print("demo1装饰完毕")
输出结果===> demo1装饰完毕

"""

经过这样一波分析是不是对上面的输出结果理解了呢!

总结:

       .装饰器是基于闭包实现的,可以简单理解为(嵌套函数);

        .装饰器的构成:

                1.需要一个嵌套函数,也就是说得有一个外部函数,有一个内部函数,内部函数定义在外部函数里面,成为内函数和外函数;

                2.内函数点用了外函数的临时变量(一个在外函数中的局部变量)或外函数的参数(形参);

                3.外函数返回的是内函数这个函数对象。

        .外函数传函数对象,内函数传函数对象的参数。

        四.有多个装饰器时, 先自底向上执行装饰器的定义,而后自顶向下执行装饰器的功能。

参考文章: https://blog.csdn.net/xiangxianghehe/article/details/77170585?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166598319216800184158868%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=166598319216800184158868&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-2-77170585-null-null.142^v58^control_1,201^v3^control_2&utm_term=python%E8%A3%85%E9%A5%B0%E5%99%A8%E8%AF%A6%E8%A7%A3&spm=1018.2226.3001.4187

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值