装饰器
装饰器在面向对象(OOP)中也叫装饰模式,是python面向对象中的一种设计模式,装饰器也可以用函数实现,其主要功能是在不改变函数的原有结构下,为该函数增加其他的一些功能,优点是可以实现代码的复用,写好一个装饰器,可以用到多个想使用该装饰器功能的函数上。
装饰器的应用
一个简单的装饰器
def a(func):
print(1)
def b(*args, **kwargs):
print(2)
func()
print(3)
# return func
return b
@a
def c():
print(4)
c()
当程序运行时:先执行@a,得到一个1和函数的对象b,b和b()是不一样的,b只是一个对象,并不会运行,然后当运行到c()的时候,相当于给了b执行的参数,然后我们会执行2,func()得到4,3,到这里程序结束
带参数的装饰器
def a(func):
print(1)
# *args将参数打包成tuple传给函数,**kwargs将参数打包成dict传给函数
def b(*args, **kwargs):
print(2)
func(*args, **kwargs)
print(3)
# return func
return b
@a
def c(d, e):
print(d + e)
c(3, 4)
这里最后就相当于执行了a(c(d, e))函数,这里的b()就相当于c()。
当装饰器本身需要传入参数
如果装饰器本身需要传入参数,那么就需要编写一个返回装饰器的高阶函数,举个例子:
def a(n, m):
def decorator(func):
def wrapper(*args, **kwargs):
print("%s1" % n)
func(*args, **kwargs)
print("%s3" % m)
return func
return wrapper
return decorator
@a('装饰部分', '装饰部分')
def b(d, e):
print(d + e)
b(3, 4)
这个装饰器的效果其实是这样的:
b = a(‘装饰部分’, ‘装饰部分’)(b(3, 4))
首先执行a(‘装饰部分’, ‘装饰部分’),返回decorator()函数,参数为b(3, 4)函数,最终返回wrapper函数。
以上两种定义装饰器的方法都没有问题,但是,python中,一切皆对象,函数也是对象,有__name__属性,但是经过装饰器装饰过后,你在去查看被装饰函数的__name__属性的话,发现它的值从原来的’b‘变成了’wrapper‘!!
因为最终返回的函数wrapper他的__name__属性就是wrapper,所以,需要把原始函数的__name__属性的值复制到wrapper()函数中,否则,某些依赖于函数签名的代码执行就会出错。
不需要编写wrapper.__name__ = func.__name__,python中内置了functools.wraps就是干这个事的,所以一个完整的装饰器写法如下:
from functools import wraps
def a(n, m):
def decorator(func):
# 将原函数的__name__等属性复制到wrapper()函数中
@wraps(func)
def wrapper(*args, **kwargs):
print('%s1' % n)
func(*args, **kwargs)
print('%s3' % m)
return func
return wrapper
return decorator
@a('装饰部分', '装饰部分')
def b(d, e):
print(d + e)
b(3, 4)
print(b.__name__)