python高级语法之闭包和装饰器详解

编辑: admin 分类: python 发布时间: 2021-12-24 来源:互联网
目录
  • 一、闭包
  • 二、一个简单的例子
  • 三、装饰器
    • 3.1 简单装饰器
      • 3.1.1 使用装饰器的语法糖
      • 3.1.2 装饰器的执行时机
    • 3.2 通用装饰器
      • 3.2.1 装饰带有参数的函数
      • 3.2.2. 装饰带有返回值的函数:
      • 3.2.3 实现通用装饰器
    • 3.3 多个装饰器的使用
      • 3.4 带有参数的装饰器
        • 3.5 类装饰器

        一、闭包

        闭包的形成条件:

        1.函数嵌套。

        2.内部函数使用了外部函数的变量或者参数。

        3.外部函数返回了使用外 部变量的内部函数。

        二、一个简单的例子

        def func_out(num1):
            def inner(num2):
                res = num1 + num2
                print(res)
            return inner
        # a = func_out(10)(10)
        a = func_out(10)
        a(10)
        

        闭包修改外部函数的变量:

        在闭包内修改外部函数的变量需要使用nonlocal关键字

        def func_out():
            # 外部函数的变量
            num1 = 10
            def func_inner():
                # 在闭包内修改外部函数的变量
                nonlocal num1
                num1 = 20
                res = num1 +20
                print(res)
            print("修改前的变量", num1)
            func_inner()
            print("修改后的变量", num1)
            return func_inner
        new_func = func_out()
        new_func()
        

        三、装饰器

        3.1 简单装饰器

        装饰器就是给已有函数增加额外功能的函数,它本质上就是一个闭包函数,也就是说也是一个函数嵌套。装饰器的功能特点:

        1.不修改已有函数的源代码

        2.不修改已有函数的调用方式

        3.给已有函数增加额外的功能

        用户在发表评论的时候需要验证用户是否登录,我们首先会想到去修改原来的函数,在函数里面添加一些功能,但是在现在这分工合作的时代,这样的修改很容易出现修改了祖传的代码后,函数出现问题,也影响代码的高效复用。为了能够不重新修改原来的评论的代码,实现高水平的代码复用。

        原本的函数及其调用:

        def comment():
            print("执行祖传代码.....")
            print("发表评论")
        # 调用评论功能
        comment()

        自己手写一个实现装饰器功能的函数实现登录验证:

        def decorator(func):
            def inner():
                print('正在验证登录者身份...\n验证成功')
                func()
            return inner
        
        
        def comment():
            print("执行祖传代码.....")
            print("发表评论")
        # 调用评论功能
        comment = decorator(comment)
        comment()
        

        输入结果:

        正在验证登录者身份…
        验证成功
        执行祖传代码…
        发表评论

        3.1.1 使用装饰器的语法糖

        装饰器的语法糖写法:@装饰器名称

        如例子可以改写为:

        def decorator(func):
            def inner():
                print('正在验证登录者身份...\n验证成功')
                func()
            return inner
        
        @decorator
        def comment():
            print("执行祖传代码.....")
            print("发表评论")
        
        # 调用函数
        comment()
        

        运行结果:

        正在验证登录者身份…
        验证成功
        执行祖传代码…
        发表评论

        3.1.2 装饰器的执行时机

        先说结论:在使用装饰器语法糖时,会先将该装饰器函数执行一遍。

        def decorator(func):
            # 测试装饰器的执行时机
            print('--remark1----')
            def inner():
                print('正在验证登录者身份...\n验证成功')
                func()
            print('----remark2---')
            return inner
        
        @decorator
        def comment():
            print("执行祖传代码.....")
            print("发表评论")
        

        输出结果:

        –remark1----
        ----remark2—

        3.2 通用装饰器

        装饰的函数可能有参数传递,或者有返回值,上面写的例子中,如果依然用上面的方法及逆行装饰器的装饰将会出现问题,那是否有一个通用的装饰器能够装饰任意函数呢?

        3.2.1 装饰带有参数的函数

        def logging(fn):
            def inner(num1,num2):
                print('执行了一次计算')
                fn(num1,num2)
            return inner
        # 使用装饰器装饰函数
        @logging
        def sum_num(a,b):
            result = a + b
            print(result)
            
        sum_num(1,2)
        

        3.2.2. 装饰带有返回值的函数:

        def logging(fn):
            def inner(num1,num2):
                print('执行了一次计算')
                result = fn(num1,num2)
                return result
            
            return inner
        # 使用装饰器装饰函数
        @logging
        def sum_num(a,b):
            result = a + b
            return result
            
        print(sum_num(1,2))
        

        3.2.3 实现通用装饰器

        *args: 用于接收元组参数,可传可不传

        **kwargs: 用于接收字典类型参数,可传可不传

        def logging(fn):
            def inner(*args, **kwargs):
                result = fn(*args, **kwargs)
                return result
            return inner
        
        @logging
        def sum_num(a,b):
            result = a + b
            return result
        

        3.3 多个装饰器的使用

        多个装饰器的过程:由内到外的装饰过程,先执行内部装饰器,再执行外部装饰器。

        原理剖析:content = make_div(make_p(content))

        分步拆解:content = make_p(content), 内部装饰器完成content=make_p.inner, content = make_div(make_p.inner)

        def make_div(func):
            print("make_div装饰器执行了")
            def inner():
                # 在内部函数对已有函数进行装饰
                result = "<div>" + func() +"</div>"
                return result
            return inner
        
        def make_p(func):
            print("make_p装饰器执行了")
            def inner():
                # 在内部函数对已有函数进行装饰
                result = "<p>" + func() +"</p>"
                return result
            return inner
        
        @make_div
        @make_p
        def content():
            return "人生苦短,我用Python"
        

        输出:

        make_p装饰器执行了
        make_div装饰器执行了
        <div><p>人生苦短,我用Python</p></div>

        3.4 带有参数的装饰器

        带有参数的装饰器时机上就是定义了一个函数,让函数接收参数,再函数内部返回该装饰器。

        如定义一个能够判断加减的装饰器:

        def return_decorator(flag):
            def decorator(func):
                def inner(a,b):
                    if flag == '+':
                        print("正在进行加法运算")
                    elif flag == '-':
                        print("正在进行减法运算")
                    func(a,b)
                return inner
            return decorator
        @return_decorator('+')
        def add_num(a,b):
            print(a+b)
        
        add_num(1,5)
        

        3.5 类装饰器

        使用类装饰已有函数。

        class MyDecorator(object):
            def __init__(self,func):
                self.__func = func
            # 实现__call__方法,让对象变成可调用的对象,
            # 可调用的对象能够像函数一样被使用。
            def __call__(self,*args,**kwargs):
                # 对已有参数进行封装
                print('--正在进行装饰-----')
                self.__func()
                
        @MyDecorator
        def show():
            print("hello")
        
        # 指向MyDecorator类创建实例对象--> show()==> 对象()
        show()
        

        输出:

        –正在进行装饰-----
        hello

        到此这篇关于python高级语法之闭包和装饰器详解的文章就介绍到这了,更多相关python闭包和装饰器内容请搜索hwidc以前的文章或继续浏览下面的相关文章希望大家以后多多支持hwidc!