闭包、装饰器

闭包

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

     

posted @ 2018-11-04 16:59  Kmnskd  阅读(118)  评论(0编辑  收藏  举报