美文网首页Python知识锦集
Python mini-web框架3:装饰器

Python mini-web框架3:装饰器

作者: IIronMan | 来源:发表于2019-01-08 21:55 被阅读0次

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

需求:在不改变下面 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())
    

    打印结果:

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

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

相关文章

网友评论

    本文标题:Python mini-web框架3:装饰器

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