python 闭包与装饰器

572 阅读2分钟

1.什么是闭包

如果一个函数内部定义了一个函数,我在称外面这个函数为外函数,里面的这个函数为内函数

如果内函数内部使用了外函数的临时变量,并且外函数的返回值是内函数的引用,这种形式称之为函数闭包

2.闭包的三要素

  • 函数嵌套
  • 外函数返回了内函数的引用
  • 内函数使用外函数的临时变量

3.闭包的作用

  • 闭包可以实现惰性求值

  • 闭包可以保持函数的特定状态

    1.惰性求值

    在编程语言理论中,惰性求值目的是要最小化计算要做的工作。惰性计算的最重要的好处
    是它可以构造一个无限的数据类型。在延迟求值特别用于函数式编程语言中。在使用延迟
    求值的时候,表达式不在它被绑定到变量之后就立即求值,而是在改值被取用的时候求值
    意义:
    建立可计算的无限列表而没有妨碍计算的无限循环或大小问题。
    例如,可以建立生成无限斐波那契数列表的函数(经常叫做“流”)。
    第n个斐波那契数的计算仅是从这个无限列表上提取出这个元素,
    它只要求计算这个列表的前n个成员。
    
    def lazy_sum(*args):
        def sum():
            res = 0
            for i in args:
                res = res + i
            return res
        return sum
    func = lazy_sum(1,2,3,4,5)
    func()
    

    廖雪峰 link

    2.状态保持

    def func1()
        name = "python"
        def func():
            print("I like %s" % name)
        return func
    func = func1()
    func()
    如上图所示,在func函数外面在包含一层函数func1,
    再把func1函数的返回结果赋值给func这个变量
    此时func就是一个闭包函数了,把func函数加括号就可以执行了
    而且我们一定知道,此时func函数的执行结果
    一定会打印"I likepython"这句话,
    而且不管func函数在程序的哪个位置被调用,执行结果都是一样的
    

装饰器的作用

    def test(func):
        def call_func():
            print("-------")
            func()
            print("-------")
        return call_func
        
    @test #等同于 f1 = test(f1)
    def f1():
        print("hhhhhh")

在不违反“开放封闭”原则的基础上,对原先的函数进行功能 扩充

  • 同一个装饰器可以对多个函数进行装饰
  • 每装饰一次都会产生一个闭包,被装饰的函数指向函数call_func,func形参指向了原函数
  • 只要遇到@+装饰器的名称,立马进行装饰

多个装饰器对同一个函数进行装饰

  • 装饰的时候装饰顺序自下向上的
  • 装饰后函数的执行顺序是自上向下
通用装饰器的写法:
    def set_func(func):
        # 函数声明,*带包可以接收多个参数
        def call_func(*args,**kwargs):
            print("---权限1-----")
            # * 表示拆包
            ret = func(*args,**kwargs) 
            print("----权限2----")
            return ret
        return call_func