这一节我们承接上一讲,继续讲解与函数装饰器相关的语法知识
5. 参数化装饰器
到目前为止,我们所接触到的装饰器都是不带参数的,但有时给装饰器适当传入一些参数,能让装饰器以更恰当的方式装饰原函数,而这就涉及到参数化装饰器了。先明确一点,当我们把一个装饰器参数化以后,这个装饰器就不再是装饰器了,而是一个能返回装饰器的工厂函数。这个工厂函数接收参数,然后输出更加切合我们需求的装饰器。
我们先来看一个小例子。

上面这段代码的执行顺序就是先调用add函数,返回一个真正的装饰器,然后@与这个返回的装饰器一道装饰原函数eggs。不同于以往的装饰器,现在我们可以通过传入extra_n参数的值,来控制装饰器的装饰效果。而我们之所以能够传参,是因为我们对原本的装饰器做了一层封装,让外面那层可以接收参数,然后再利用函数闭包的特性,间接的把参数传了进去。
6. functools.wraps
在第一讲里我写到过一个极简的装饰器,就是把接收的函数原封不动的返回过来。

现实是,装饰器返回的函数通常和原函数通常不是同一个。哪怕返回的那个函数和原函数的功能一模一样也是如此。

这会导致一个问题,就是虽然原函数的功能被保留下来了,但原函数的信息在这个过程被替换为一个通用的wrapper函数的信息。

如此一来,未来对代码进行调试的时候就不太方便了。解决这个问题的关键在于要把原函数关于自身的信息给到新函数,而不仅仅满足于在新函数中调用原函数,这只是把原函数的功能给到了新函数。具体的解决办法,Python早就帮我们想好了,只需新增一行代码就能完美解决这个问题。

这里我们用Python自带的装饰器对我们要返回的新函数再做一遍装饰,使之保留原函数的属性信息。然后再看看关于原函数的帮助信息,这回就能顺利看到了。所以以后碰到需要自己写装饰器时,一定要记得把这行代码加上呀,能省不少事。

7. 可选参数的装饰器
我们来改一下上面的add函数,让它变得更通用。我们希望这个add函数能根据所接收到的参数灵活控制自身的行为,即它既可以当装饰器工厂函数用又可以当装饰器用。

下面是代码的执行情况

小结
这一篇再加上上一篇,关于函数装饰器方面的基础语法和概念就讲的差不多了,下一篇就要进入到类装饰器了,大家一起加油吧~
网友评论