Python mini-web框架3:装饰器

一、看一个例子,来引出装饰器

需求:在不改变下面 test() 函数的情况下,执行函数的情况下先进行其他的步骤,看下面的实现

def set_func(func):

    print("----开始装饰----")

    def run_func():
        print("----验证权限1----")
        func()
    return run_func


def test1():
    print("----test----")

test1 = set_func(test1)
test1()

执行结果是:

----开始装饰----
----验证权限1----
----test----
引出装饰器
  • 分析:test1 = set_fun(test1) 改变了 test1() 的指向,指向了闭包内的run_func()函数,在test()执行的时候,执行的是run_func()函数内的代码
  • 优化: 不想写 test1 = set_fun(test1) 这句代码,我们可以在 def test1():上面写 @set_fun,我们在下面具体看使用。

二、装饰器的介绍以及参数

  • 2.1、简单的来说:一个闭包对一个函数进行装饰就组成了装饰器,如下的例子,@set_fun是一种 语法糖

    def set_func(func):
    
         print("----开始装饰----")
    
         def run_func():
    
             print("----验证权限1----")
             func()
         return run_func
    
    
    @set_func    # @set_fun 与 test1 = set_func(test1) 等价
    def test1():
    
        print("----test----")
    
    test1()
    

    提示: @set_fun 与 test1 = set_fun(test1) 等价

  • 2.2、装饰器对有 单个参数 函数的装饰(说白了就是传参)

    def set_func(func):
    
         print("----开始装饰----")
    
         def run_func(num):
    
              print("----验证权限1----")
              func(num)
         return run_func
    
    
    @set_func
    def test1(num):
    
         print("----test----%d"%num)
    
    test1(3)
    

    提示:test1指向的是闭包内的run_func函数,传的参数也是给run_func,函数内再调用test1函数,不要绕,好好理解下

  • 2.3、不定长参数的函数装饰(说白了就是参数不定),如下例子

    def set_func(func):
    
        print("----开始装饰----")
    
        def run_func(*args,**kwargs):
    
            print("----验证权限1----")
            func(*args,**kwargs)
        return run_func
    
    
    @set_func
    def test1(num,*args,**kwargs):
    
        print("----test----%d"%num,args,kwargs)
    
    test1(3,2,1,a="1")
    

    打印结果是:

    ----开始装饰----
    ----验证权限1----
    ----test----3 (2, 1) {'a': '1'}
    

    注意:

    • 闭包 里面的 func(*args,**kwargs) 中的 *args**kwargs是解包的意思,传参不能直接传元组与字典,要解包
    • 不可以传 func(args,kwargs),必挂,这样是传了两个参数,一个元组,一个字典,是不对的
  • 2.4、对应有返回值函数进行装饰、通用装饰器

    def set_func(func):
    
          print("----开始装饰----")
    
          def run_func(*args,**kwargs):
    
                print("----验证权限1----")
                return func(*args,**kwargs) # 拆包
          return run_func
    
    
    @set_func
    def test1(num,*args,**kwargs):
    
          print("----test----%d"%num,args,kwargs)
          return "OK"
    
    @set_func
    def test2():
    
          return "OK2"
    
    test1(3,2,1,a="1")
    print(test2())
    

    打印结果是:

    ----开始装饰----
    ----开始装饰----
    ----验证权限1----
    ----test----3 (2, 1) {'a': '1'}
    ----验证权限1----
    OK2
    
对应有返回值函数进行装饰、通用装饰器
  • 2.5、多个装饰器对同一个函数进行装饰

    def set_func1(func):
    
         print("----开始装饰1----")
    
         def run_func1(*args,**kwargs):
    
             print("----验证权限1----")
             func(*args,**kwargs) # 拆包
         return run_func1
    
    
    def set_func2(func):
    
         print("----开始装饰2----")
    
         def run_func2(*args,**kwargs):
    
             print("----验证权限2----")
             func(*args,**kwargs) # 拆包
         return run_func2
    
    
    @set_func1
    @set_func2
    def test1(num,*args,**kwargs):
    
          print("----test----%d"%num,args,kwargs)
    
    test1(3,2,1,a="1")
    

    打印结果:

    ----开始装饰2----
    ----开始装饰1----
    ----验证权限1----
    ----验证权限2----
    ----test----3 (2, 1) {'a': '1'}
    

    提示:当多个装饰器装饰同一个函数的时候,装饰从下往上装饰,也就是上面例子中先装饰 set_func2,再装饰set_func1
    装饰器在调用之前就已经装好了,组成一个大的闭包空间;执行的时候,先执行后装饰的装饰器里面的代码,后执行前一个被装饰的代码,依次类推,最后执行第一个装饰的闭包内的代码。

  • 2.6、对于同一个装饰器,对多个函数进行装饰
    分析:对于同一个装饰器,对多个函数进行装饰的时候,在没调用之前就会进行装饰,每装饰一个就生成一个闭包。闭包内外部函数的变量指向原函数

    def set_func(func):
    
          print("----开始装饰----")
    
          def run_func(*args,**kwargs):
    
                 print("----验证权限----")
                 func(*args,**kwargs) # 拆包
          return run_func
    
    
    @set_func
    def test1(num,*args,**kwargs):
    
          print("----test1----%d"%num,args,kwargs)
    
    
    @set_func
    def test2(num,*args,**kwargs):
    
          print("----test2----%d"%num,args,kwargs)
    
    test1(3,2,1,a="1")
    test2(4,5,6,a="2")
    

    打印结果:

    ----开始装饰----
    ----开始装饰----
    ----验证权限----
    ----test1----3 (2, 1) {'a': '1'}
    ----验证权限----
    ----test2----4 (5, 6) {'a': '2'}
    
  • 2.7、用类对函数进行装饰

    class Test(object):
        """docstring for ClassName"""
        def __init__(self, func):
      
            self.func = func
    
        def __call__(self):
    
            print("这里是装饰器添加的功能")
            return self.func()
    
    
    @Test  # 相当于 get_str = Test(get_str)
    def get_str():
    
         return "测试"
    
    
    print(get_str())
    

    打印结果:

    这里是装饰器添加的功能
    测试
    

三、带有参数的装饰器,是装饰器加参数,如下

def set_level(level):

    def set_func(func):
    
        def call_func(*args,**kwargs):

           if level ==1 :
                print("权限验证-- %d"%level)
           elif level ==2 :
                print("权限验证-- %d"%level)
           else:
                print("权限验证-- %d"%level)

           func(*args,**kwargs)
        
        return call_func

    return set_func


@set_level(9)
def test1():

    print("------test1------")


test1()
  • 分析:上面就是给装饰器加参数set_level(9):
    • 1、调用set_level并且将9当做实参传递
    • 2、用上一步调用的返回值当做装饰器对test1函数进行装饰

总结:不要觉得装饰器很难,其实它就是:函数的指向的改变,以闭包为例,闭包作为另一个函数的装饰器,装饰后,在闭包的内部函数再去调用函数,其实就是在函数执行之前先调用闭包内的代码。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 包(lib)、模块(module) 在Python中,存在包和模块两个常见概念。 模块:编写Python代码的py...
    清清子衿木子水心阅读 3,939评论 0 27
  • 在学习Python的过程中,我相信有很多人和我一样,对Python的装饰器一直觉得很困惑,我也是困惑了好久,并通过...
    愚灬墨阅读 522评论 1 1
  • 写在前面的话 代码中的# > 表示的是输出结果 输入 使用input()函数 用法 注意input函数输出的均是字...
    FlyingLittlePG阅读 3,294评论 0 9
  • 1、登陆mysql数据库 mysql -u root -p 查看user表 mysql> use mysql;Da...
    lycium阅读 3,604评论 0 1
  • 凛冽寒风萧萧瑟,百草枯,叶归土。鹧鸪双飞乐争吵,盘旋飞,无地落。 伊人红妆为谁翘,粉黛娇颜忙嬉闹。独吾一人哂笑。
    伊晓一阅读 263评论 2 1

友情链接更多精彩内容