zoukankan      html  css  js  c++  java
  • 装饰器语法糖运用

    装饰器语法糖运用

    • 前言:函数名是一个特性的变量,可以作为容器的元素,也可以作为函数的参数,也可以当做返回值。

    • 闭包定义:

      • 内层函数对外层函数(非全局)变量的引用,这个内层函数就可以成为闭包

      • 在Python中我们用__closure__来检查函数是否是闭包

      • def func1():
            name = '张三'
        
            def func2():
                print(name)  # 能够访问到外层作用域的变量
            func2()
            print(func2.__closure__)  # (<cell at 0x1036c7438: str object at 0x10389d088>,)
        
        func1()
        print(func1.__closure__)  # None
        
    • 装饰器

      • 前言:软件设计原则:开闭原则,又称开放封闭原则

        • 指对扩展代码的功能是开放的,但对修改源代码是封闭的,
      • def create_people():
            print('女娲真厉害,捏个泥吹口气就成了人!')
        
        
        def a(func):
            def b():
                print('洒点水')
                func()
            return b
        
        ret = a(create_people)
        ret()
        
      • 通过装饰器语法等同于

      • def a(func):
            def b():
                print('洒点水')
                func()
            return b
        
        
        @a  # 装饰器语法糖的作用就是上述函数ret()
        def create_people():
            print('女娲真厉害,捏个泥吹口气就成了人!')
        
        create_people()
        
    • 装饰带返回值的函数,即return出被装饰函数的执行结果

      • def foo(func):  # 接收的参数是一个函数名
            def bar():  # 定义一个内层函数
                print("这里是新功能...")  # 新功能
                r = func()  # 在内存函数中拿到被装饰函数的结果
                return r  # 返回被装饰函数的执行结果
            return bar
        
        
        # 定义一个有返回值的函数
        @foo
        def f1():
            return '嘿嘿嘿'
        
        
        # 调用被装饰函数
        ret = f1()  # 调用被装饰函数并拿到结果
        print(ret)
        
    • 装饰带参数的函数

      • def func1(func):              # 接收的参数为一个函数名
            def inner(*args, **kwargs):     # 这里需要定义和被装饰函数相同的参数
                print("新功能")                # 新功能
                ret = func(*args, **kwargs)     #被装饰的函数和参数
                print("新功能")         
                return ret
            return inner
        
        # 定义一个需要俩个参数的函数
        @func1
        def func(a, b):
            return a + b
        
        
        ret = func(3, 5)
        print(ret)
        
    • 带参数的装饰器 即在装饰器外在写一层函数,从而使其带参数

      • def d(a=None):        # 定义一个外层函数,给装饰器传参数
            def func1(func):  # 接收的是一个函数名
                def inner(*args, **kwargs): # 被装饰的函数,和参数
                    if a:
                        print(f"欢迎来到{a}")   #添加新功能
                    else:
                        print("欢迎来到王者荣耀")  
                    func(*args, **kwargs)
                return inner
            return func1
        
        
        # @d("英雄联盟")
        # def func(st):
        #     print(st)
        # func("敌军还有三十秒到达战场")
                                      # 欢迎来到英雄联盟
                                      # 敌军还有三十秒到达战场
        
        @d()
        def func(st):
            print(st)
        func("敌军还有三十秒到达战场")
        # 欢迎来到王者荣耀
        # 敌军还有三十秒到达战场
        
    • 装饰器修复技术

      • 定义:被装饰的函数最终都会失去本来的__doc__等信息, Python给我们提供了一个修复被装饰函数的工具。

      • from functools import wraps    #导入
        print(f1.__doc__)
        print(f1.__name__)
        
    • 多个装饰器装饰同一函数

      • from functools import wraps
        
        def wrapper2(func):
            @wraps(func)
            def inner(*args, **kwargs):
                r = func(*args, **kwargs)
                return f"<2>{r}</2>"
            return inner
        
        def wrapper1(func):
            @wraps(func)
            def inner(*args, **kwargs):
                r = func(*args, **kwargs)
                return f"<1>{r}</1>"
            return inner
        
        @wrapper2
        @wrapper1
        def func(a):
            return a
        
        
        print(func("Hello World!!"))  #<2><1>Hello World!!</1></2>
        
      • def foo1(func):
            print("d1")
        
            def inner1():
                print("inner1")
                return "<i>{}</i>".format(func())
        
            return inner1
        
        
        def foo2(func):
            print("d2")
        
            def inner2():
                print("inner2")
                return "<b>{}</b>".format(func())
        
            return inner2
        
        
        @foo1
        @foo2
        def f1():
            return "Hello Andy"
        
        # f1 = foo2(f1)  ==> print("d2") ==> f1 = inner2
        # f1 = foo1(f1)  ==> print("d1") ==> f1 = foo1(inner2) ==> inner1
        
        ret = f1()  # 调用f1() ==> inner1()  ==> <i>inner2()</i>  ==> <i><b>inner1()</b></i> ==> <i><b>Hello Andy</b></i>
        print(ret)
        
    • 类装饰器

      • class D(object):
            def __init__(self, a=None):
                self.a = a
                self.mode = "装饰"
        
            def __call__(self, *args, **kwargs):
                if self.mode == "装饰":
                    self.func = args[0]  # 默认第一个参数是被装饰的函数
                    self.mode = "调用"
                    return self
                # 当self.mode == "调用"时,执行下面的代码(也就是调用使用类装饰的函数时执行)
                if self.a:
                    print("欢迎来到{}页面。".format(self.a))
                else:
                    print("欢迎来到首页。")
                self.func(*args, **kwargs)
        
        
        @D()
        def index(name):
            print("Hello {}.".format(name))
        
        
        @D("电影")
        def movie(name):
            print("Hello {}.".format(name))
        
        if __name__ == '__main__':
            index('张三')
            movie('张三')
        
    • 装饰类

      • # 定义一个类装饰器
        class D(object):
            def __call__(self, cls):
                class Inner(cls):
                    # 重写被装饰类的f方法
                    def f(self):
                        print('Hello 张三.')
                return Inner
        
        
        @D()
        class C(object):  # 被装饰的类
            # 有一个实例方法
            def f(self):
                print("Hello world.")
        
        
        if __name__ == '__main__':
            c = C()
            c.f()
        
  • 相关阅读:
    IDEA 快捷键
    Python3开启自带http服务
    redis-creating server tcp listening socket 127.0.0.1:6379: bind No error
    moco的使用方法
    tomcat程序闪退,如何让tomcat不闪退,可以看见报错
    java 项目中Error linstenerStart 报错解决方法
    Linux 常用命令
    TS数据类型及语法
    RabbitMQ的下载和安装
    vue 控制 input 的 disabled
  • 原文地址:https://www.cnblogs.com/yuncong/p/9886555.html
Copyright © 2011-2022 走看看