首页 > 技术文章 > Python - 装饰器 & 闭包(针对初学者)

yidada 2019-03-21 17:31 原文

一、装饰器

  本身就是函数,都是用def语法来定义的,为其他函数添加附加功能。

二、应用场景

  假设目前编写的函数已经上线运行了,某一天,产品有个需求,要在这个里面新增一个功能,那怎么去做这个事?最简单的就是:重新编码。但是问题是程序已经运行了,修改程序源码,会有风险发生。

  所以说,我要新增一个功能,不能够修改函数的源代码,且不改变原函数的调用方式,这个时候装饰器就出现了

闭包

  要了解装饰器首先要知道什么是闭包

  总结起来就是:

    1、外层函数返回了内存函数的引用

    2、内层函数引用了外层函数的参数

1  def out(num):  #外层函数
2 print('1')
3 def inner(): #内层函数
4 print(num)
5 print('5')
6 print('2')
7 return inner #返回了内层函数的引用
8
9 res = out(4)
10 res()

  这就是闭包,那么闭包是怎么执行的呢

1
2
4
5

 当调用out() 的时候,此时执行外层函数,输出1,输出2 ,注意:当程序执行到第3行时,只是在此声明了一个函数,并没有做任何事情,此时res接收了out的返回值(inner函数的引用)

 当调用res() 的时候,此时相当于调用inner函数,输出4,输出5,执行完毕

   

 执行内部函数的时候,外层函数的变量并没有被销毁,可以一直被调用。

def out(num):
    print('1')
    def inner(num_inner):
        print(num)
        print(num_inner)
    print('2')
    return inner

res = out(4)
res(11)
res(22)
res(33)
res(44)

   此时输出结果为

1
2
4
11
4
22
4
33
4
44

  此种应用,虽然编写函数的时候会稍微麻烦点,但是可以反复调用,不会被释放,传参数的时候也可以简化

  

装饰器

  1、只是在原来的函数基础上增加新的函数,达到在执行原来的函数之前或者之后执行新添加的功能

  2、不改变原函数的调用方式,原来调用哪个函数现在还调用哪个函数

 

示例一:

def out1(func):    #此函数相当于拓展函数
    print('外层开始执行')
    def inner1():
        print('内层开始执行')
        func()
    print('外层执行完毕')
    return inner1

@out1
def ma():       #此函数相当于原来的函数 print('这是一个主函数') ma()           #调用方式依旧是原来的调用

输出结果

外层开始执行
外层执行完毕
内层开始执行
这是一个主函数

示例二:

def out1(canshu):
    print('外层开始执行')
    def inner1():
        print('内层开始执行')
        canshu()
    print('外层执行完毕')
    return inner1

# @out1
def ma():
    print('这是一个主函数')
ma = out1(ma)
ma()

输出结果

外层开始执行
外层执行完毕
内层开始执行
这是一个主函数

可以看到上面两种方式实现了同样的功能(示例一属于闭包函数装饰了原来的函数)

可以看出 

ma = out1(ma)
ma()

只是被 语法糖 @out1 替换掉了

在函数ma上面加上了@out1,就相当于 out1(ma)

当程序执行到@定义的位置,就会自动执行闭包体的外层函数,当执行到原函数调用时,会自动执行闭包体的内层函数

下面附上详细图片

   

 

推荐阅读