美文网首页
闭包、装饰器

闭包、装饰器

作者: xiaohan_zhang | 来源:发表于2019-07-20 16:18 被阅读0次

    闭包

    在函数嵌套的前提下,内部函数使用了外部函数的变量,把这个内部函数成为闭包。

    • 闭包构成条件
      1.1 函数嵌套(函数里面再定义函数)
      1.2 内部函数使用外部函数的变量
      1.3 外部函数返回了内部函数
    def func_out1():
        num1 = 10
        def func_inner(num2):
            result = num1 + num2
            print(f'result = {result}')
        return func_inner
    
    
    # 闭包保存了外部函数的变量num1,执行闭包都是在num1 = 10的基础上进行计算。
    func_out1()(2)  # result = 13
    f = func_out1()
    f(3)    # result = 14
    
    
    def func_out2(num1):
        def func_inner(num2):
            result = num1 + num2
            print(f'result = {result}')
        return func_inner
    
    
    f = func_out2(1)
    f(1)    # result = 2
    
    • 修改外部函数中的变量
      python3: nonlocal修饰
    def func_out3(num1):
        def func_inner():
            # 在闭包内修改外部函数变量,需要使用nonlocal关键字修饰
            nonlocal num1
            num1 += 1
    
        print(f'修改前:num1 = {num1}')
        func_inner()
        print(f'修改后:num1 = {num1}')
        return func_inner
    
    
    func_out3(1)()
    
    
    def func_out4(num1):
        def func_inner():
            nonlocal num1
            num1 += 1
            return num1
    
        return func_inner
    
    
    f = func_out4(10)
    print(f())  # 11
    

    装饰器

    装饰器本质是一个闭包函数,可以对已有函数进行额外的功能扩展。
    装饰器执行时机:
    当前模块加载完成时,装饰器会立即执行,对已有函数进行装饰

    • 装饰器(decorator)功能
    1. 不修改已有函数的源代码
    2. 不修改已有函数的调用方式
    3. 给已有函数增加额外功能
    • 装饰器语法格式
    def decorator(func):    # func被装饰的目标函数
        def inner():
            '''执行函数之前'''
            func()      # 执行被装饰的目标函数
            '''执行函数之后'''
        return inner
    # 装饰器语法糖用法:
    @装饰器名称 修饰被装饰函数
    
    • 装饰器示例
      1. 装饰无参数的函数
    # 如果闭包函数有且只有一个参数,并且是函数类型,那么这个闭包函数称为装饰器
    def outter(func):
        def inner():
            print("登录验证")
            func()
        return inner
    
    # 装饰器语法糖写法 等价于comment = outter(comment)
    @outter
    def comment():
        print("发表评论")
    
    
    comment()
    # 调用装饰器对已有函数进行装饰
    # comment = outter(comment)
    # comment()
    """
    登录验证
    发表评论
    """
    
    1. 装饰有参数的函数
    def decorator_add(func):
        def inner(num1, num2):
            print('正在努力执行加法运算....')
            func(num1, num2)
        return inner
    
    
    @decorator_add
    def add_num(num1, num2):
        result = num1 + num2
        print(f'结果为:{result}')
    
    
    add_num(1, 4)
    """
    正在努力执行加法运算....
    结果为:5
    """
    
    1. 装饰器带有返回值的函数
    def decorator_add2(func):
        def inner(num1, num2):
            print('2正在努力执行加法运算....')
            return func(num1, num2)
        return inner
    
    @decorator_add2
    def add_num2(num1, num2):
        return num1 + num2
    
    
    result = add_num2(1, 2)
    print(f'有返回值函数:result = {result}')
    '''
    正在努力执行加法运算....
    有返回值函数:result = 3
    '''
    
    1. 装饰带有不定长参数的函数
    def decorator_add3(func):
        def inner(*args, **kwargs):
            print('3正在努力执行加法运算....')
            return func(*args, **kwargs)    # 拆包
        return inner
    
    @decorator_add3
    def add_num3(*args, **kwargs):
        print("-----call_func:args =", args, ",kwargs =", kwargs)
        result = 0
        for value in args:
            result += value
        for value in kwargs.values():
            result += value
        return result
    
    
    result = add_num3(1, 3)
    print(f'不定长参数函数:result = {result}')
    result = add_num3(1, 3, num=4)
    print(f'不定长参数函数:result = {result}')
    '''
    3正在努力执行加法运算....
    -----call_func:args = (1, 3) ,kwargs = {}
    不定长参数函数:result = 4
    3正在努力执行加法运算....
    -----call_func:args = (1, 3) ,kwargs = {'num': 4}
    不定长参数函数:result = 8
    '''
    
    1. 通用装饰器
    def decorator(func):
        def inner(*arg, **kwargs):
            print('通用装饰器')
            res = func(*arg, **kwargs)
            return res
        return inner
    
    
    @decorator
    def show():
        print('哈哈哈哈哈哈')
    
    
    show()
    
    1. 多个装饰器对同一个函数装饰
    """
    多个装饰器的执行过程:
    由内到外装饰,先执行内部装饰器,再执行外部装饰器
    """
    def make_p(func):
        print('make_p装饰器执行了')
        def inner():
            content = '<p>' + func() + '</p>'
            return content
        return inner
    
    def make_div(func):
        print('make_div装饰器执行了')
        def inner():
            content = '<div>' + func() + '</div>'
            return content
        return inner
    
    @make_div
    @make_p
    def content():
        return "装饰器使用练习"
    
    
    print(content())
    """
    make_p装饰器执行了
    make_div装饰器执行了
    <div><p>装饰器使用练习</p></div>
    """
    
    1. 带有参数的装饰器
      带有参数的装饰器就是使用装饰器的时候,可以传入指定参数;
      语法格式:@装饰器(参数...)
      带有参数的装饰器其实就是在装饰器外面又包了一层函数,使用该函数接收参数,返回装饰器。
    def return_decorator(flag):
        def decorator(func):
            def inner(num1, num2):
                if flag == '+':
                    print('正在努力执行加法运算')
                elif flag == '-':
                    print('正在努力执行减法运算')
                func(num1, num2)
            return inner
        return decorator
    
    @return_decorator('+')
    def add_num(a, b):
        res = a + b
        print(res)
    
    @return_decorator('-')
    def sub_num(a, b):
        res = a - b
        print(res)
    
    
    add_num(2, 5)
    sub_num(5, 2)
    '''
    正在努力执行加法运算
    7
    正在努力执行减法运算
    3
    '''
    
    1. 类装饰器
    class Check(object):
        def __init__(self, func):
            self._func = func
    
        # 实现__call__方法,表示对象是一个可调用对象,可以像调用函数一样进行调用。
        def __call__(self, *args, **kwargs):
            print('添加装饰功能')
            self._func()
    
    @Check
    def show():
        print('快要下雪了')
    
    
    show()
    '''
    添加装饰功能
    快要下雪了
    '''
    
    
    • 装饰器使用场景
      1. 引入日志
      2. 函数执行时间统计
      3. 执行函数前预备处理
      4. 执行函数后清理功能
      5. 权限校验等场景
      6. 缓存

    相关文章

      网友评论

          本文标题:闭包、装饰器

          本文链接:https://www.haomeiwen.com/subject/kpdylctx.html