Python 装饰器

装饰器(Decorator)本质上是一个闭包(Closure),把一个函数作为参数返回一个替代的函数,也就是他就是一个返回函数的函数。

装饰器给原本的函数增加了新的功能,看起来好像就是用新的功能给原来的函数装饰了一番,这也就是为什么叫做装饰器的原因。

写一个简单的函数,描述一个人阐述的宣言:

 def man():
    print("我很帅")

现在增加了新的需求:不修改函数的情况下,在他说出宣言之前,首先要说一句“是啊”,可以这样写:

 def outer(fun):
    def inner():
        print("是啊")
        fun()
    return inner

 def man():
    print("我很帅")

 if __name__ == '__main__':
    f = outer(man)
    f()

为了让能让所有的人在说出“我很帅”之前都能先说“是啊”,这里给 outer() 函数传递了一个函数,并在 outer() 中返回内部函数,内部函数负责对原始函数的修饰,也就是添加新的功能。返回的内部函数由变量 f 接收,相当于拿到了内部函数的引用,接着执行这个内部函数,就是执行修饰过后的原始函数。这就是一个最简单最原始的装饰器。

从上面的例子中可以总结出装饰器的模板:

 def outer(fun):
     def inner():
         # 对原始函数的修饰
         fun()
     return inner

如果现在有一个 man() 的函数用来输出他的年龄:

 def man(age):
     print("我的年龄是%d" % age)

但是年龄不能是负数,这时候要给它增加一个判断的功能,在不修改原始函数的情况下。

 def outer(fun):
    def inner(age):
        if(age<0):
            age = 0
        fun(age)
    return inner

 def man(age):
    print("我的年龄是%d" % age)

 if __name__ == '__main__':
    f = outer(man)
    f(5)                       //最后的输出结果是 >>>我的年龄是5

这是给带参数的函数添加修饰,这时候返回的内部函数是有参数的内部函数,由变量 f 接收,再给 f 传递参数的时候,会在内部函数中对参数进行检查,之后再将参数传给原始函数。

这里可以使用装饰器的语法来代替 f 接收 return 回来的内部函数的过程。上面的代码可以改写为:

 def outer(fun):
    def inner(age):
        if(age<0):
            age = 0
        fun(age)
    return inner

 @outer #相当于 f = outer(man)
 def man(age):
    print("我的年龄是%d" % age)

 if __name__ == '__main__':
    # f = outer(man)
    man(5)

最后的输出结果为:

遇到的更多的情况是:给原始函数传递的是任意数量的参数。这时候怎么用装饰器去控制处理不知道具体数量的参数呢?

这时候就要需要写一个通用装饰器,能够接收并处理任意数量的参数,能够接收任意数量的参数的,就是可变参数了。

 def outer(fun):
    def inner(*args,**kwargs):
        print("是啊")
        fun(*args,**kwargs)
    return inner

 @outer  # 相当于 f = outer(man)
 def man(name,age):
    print("我的名字是%s,我的年龄是%d" % (name,age))

 if __name__ == '__main__':
    # f = outer(man)
    man("王也道长",5)

最后输出的结果为:

由上,我们也可以总结出通用装饰器的模板:

 def outer(fun):
    def inner(*args,**kwargs):
        # 对原始函数增加新的处理功能
        fun(*args,**kwargs)
    return inner

总结来说,装饰器就是返回了一个内部函数,在执行原始函数之前,先进入这个内部函数,对原始函数做一些预处理,这就是增加的额外的功能了,然后再在内部函数中执行原始函数。原始函数所需要的参数,由内部函数提供。因此,写装饰器的时候,把重点仍着眼于内部函数。





相关推荐

评论

  1. #1

    dUoxKpta 2019-09-06 01:15:01
    dUoxKpta

  2. #2

    WEmXeAbt 2019-09-05 22:19:17
    WEmXeAbt

  3. #3

    zuLdJdBo 2019-09-05 19:41:57
    zuLdJdBo