闭包装饰器

Posted kmnskd

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了闭包装饰器相关的知识,希望对你有一定的参考价值。

闭包

python的装饰器首先要了解闭包是什么?

  • 通常情况下我们定义一个普通函数是这样做的:

    def func():
        print (哈哈哈)
    • 普通函数的返回值默认为None,也可以自己决定return

  • 闭包函数:

    • 定义:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)。

    • 把函数作为返回值返回回来。

    def wai(n):
        def nei():
            sum_num = 0
            for i in range(n):
                sum_num = sum_num + i
            return sum_num
         return nei
    res = wai(4)
    print(res)
    print(res())
    ?
    <function wai.<locals>.nei at 0x0000016C95E0F6A8>
    6
    • 上面的例子可以看出来wai()函数的返回值是一个求和函数,对res进行调用得到6。

    • 在这个例子中,我们在函数lwai中又定义了函数nei,并且,内部函数nei可以引用外部函数wai的参数和局部变量,当wai返回函数nei时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。

    • 当我们不需要立即得到结果时,可以用闭包的方式保留这个值。

    a = wai(4)
    b = wai(4)
    print(id(a))
    print(id(b))
    ?
    3126981621416
    3126981621552
    • 上面的示例可得a和b两个对象是相互独立的,在内存中有不同的id,所以数据也是独立的。

装饰器

  • 装饰器是不修改原函数代码,也不修改其他调用该函数的代码的前提下为函数添加新功能。

  • 我的理解:普通闭包是把一般数据类型的变量当做参数传入,而装饰器则是把一个函数当做变量传入,并且在其内部调用该函数之前为其添加新的功能。

  • 看代码:

    def wai(func):
        def nei():
            print(这是函数传入之前的操作)
            func()
            print(这是函数传入之后的操作)
        return nei
    ?
    def func():
        print(我是被装饰的函数)
    ?
    res = wai(func)
    res()
    ?
    这是函数传入之前的操作
    我是被装饰的函数
    这是函数传入之后的操作
    • 例子分析:我们可以看到装饰器的流程是把函数func当做变量传入wai()函数,函数往下走就是调用nei()函数,nei()函数中紧接着又调用func();再看下面调用首先是wai(func),而wai(func)的返回值就是我们闭包里所讲是个函数,即nei函数,所以要看到print结果就要对这个返回值再次调用,把返回值保存成res,对其调用。

    • 从这段代码得出:

      • 1.函数的参数传递的其实是引用,而不是值。

      • 2.函数名也可以是一个变量,所以可以重新赋值。

      • 3.赋值操作的时候,先执行等号右边的。

  • 上面的例子看完我们再看看正经写代码时的规范。也就是用@符号代替了res = wai(func)和res()这两个步骤,方便写代码。我们只需要调用被装饰函数即可。

    def wai(func):
        def nei():
            print(这是函数传入之前的操作)
            func()
            print(这是函数传入之后的操作)
        return nei
    @wai
    def func():
        print(我是被装饰的函数)
        
    func()
    ?
    这是函数传入之前的操作
    我是被装饰的函数
    这是函数传入之后的操作

装饰器的分类

  • 普通装饰器:即不带任何参数,就是上面的例子。

  • 被装饰函数带参数:

    def wai(func):
        def nei(a):
            print(传入函数之前的操作)
            func(a)
            print(传入函数之后的操作)
        return nei
    @wai
    def func(a):
        print(我是被装饰函数的参数:,a)
    func(2)
    ?
    传入函数之前的操作
    我是被装饰函数的参数: 2
    传入函数之后的操作
  • 装饰器带有参数:

    def head(b):        
        def wai(func):
            def nei(a):
                print(我是装饰器的参数:,b)
                print(传入函数之前的操作)
                func(a)
                print(传入函数之后的操作)
            return nei
        return wai
    @head(5)
    def func(a):
        print(我是被装饰函数的参数:,a)
    func(2)
    ?
    我是装饰器的参数: 5
    传入函数之前的操作
    我是被装饰函数的参数: 2
    传入函数之后的操作
  • 两个装饰器

    def w1(func):
        print(---正在装饰--)
        def inner():
            print(---正在验证权限1--)
            func()
        return inner
    ?
    ?
    def w2(func):
        print(---正在装饰2--)
        def inner():
            print(---正在验证权限2--)
            func()
        return inner
    ?
    # 只要python解释器执行到了这个代码,那么就会自动的进行装饰,而不是等到调用的时候才装饰的
    @w2
    @w1
    def f1():
        print(---f1)
    ?
    f1()
    ?
    输出结果:
    ---正在装饰--
    ---正在装饰2--
    ---正在验证权限2--
    ---正在验证权限1--
    ---f1

     

以上是关于闭包装饰器的主要内容,如果未能解决你的问题,请参考以下文章

9.23闭包函数/装饰器/迭代器/生成器

CSIC_716_20191112闭包函数和装饰器

python闭包函数装饰器

python函数下篇装饰器和闭包,外加作用域

python闭包及装饰器

装饰器和闭包