Python中函数装饰器@
##Python中函数装饰器@
Python中的@是函数修饰器,它其实是种语法糖。本身并不会语言的功能产生影响,但可以更方便程序员的使用。让代码看起来更清晰和简洁。
1 | def funA(fn): |
在上面这段代码中我们需要注意几个地方:
- 这里定义了两个函数,分别是funA和funB。而funA是有参数的。
- 在这段代码的最后还执行了一行语句。函数funB被当作参数传入了funA。并且,把funB重新赋值成了funA(funB)的返回值。
在上面的代码中有一件事悄悄发生了,那就是函数funB的地址已经找不到了。
代码中的函数funB已经成为了funA(funB)的返回值。如果返回值为None,那funB则为None。
如果使用了函数装饰器@,那上面的代码与下面的代码是等价的。
1 | #funA 作为装饰器函数 |
这段代码同样有值得注意的地方:
- 函数funA是必须有参数的,因为它需要把函数funB作为参数传入。
- 语句funB = funA(funB)似乎“消失”了。但这条语句依然会被执行,只是被隐藏了。
结合上面两段代码来看,函数装饰器@的作用就是把被装饰函数传给装饰函数,以此来进行功能上的扩展。但需要强调,被装饰函数会被重新赋值为装饰器的返回值!
##单个修饰器,修饰不带参数的函数
函数装饰器@经常可以被用来,插入日志、性能测试、事务处理、记录时间戳等等。
假设现在我们新写了个功能,需要用日志进行测试。但我们不应该直接把日志功能加入到新的函数中。因为这会导致功能耦合,代码的可读性非常的差。在这种情况下,我们可以来看个使用函数装饰器@的例子:
1 | def log(function): |
代码执行结果如下:
1 | log start... |
上面这段代码等价于:
1 | def log(function): |
因为函数log返回了一个函数给test,实际上也就是返回了函数的地址给test。这也test才能被调用。如果函数log返回None,那test的地址内容也就是None,会抛出错误:
TypeError: ‘NoneType’ object is not callable
因为标识符test为None,而我们却想把空值None当作函数来调用,这当然是不可行的。
##单个修饰器,修饰带参数的函数
上面被修饰的函数是没有传入参数的,如果我们新写的函数是有传入参数的怎么办呢?我们可以这样写:
1 | def log(function): |
代码的执行结果如下:
1 | log start... |
使用“*arg, **kwargs”的话被装饰函数test的所有参数都会被传入到装饰器中。
##多个修饰器
一个被函数可以被多个修饰器修饰。假设,我某个函数我既要观察日志,也需要记录时间戳。我们就可以使用函数修饰器来进行多个事务上的处理。
1 | def log(function): |
代码的执行结果如下:
1 | time start... |
在上面的修饰器会先被执行。
还需要考虑一个问题,修饰器可以嵌套么?
1 | def log(function): |
对于上面这段代码,并没有按照预期的那样正常运行,会抛出错误。即使在内置函数wrapper加上返回值return function,也不会按照预期的那样执行函数test的内容。
尽量还是不要使用嵌套的函数修饰符。