Python里的装饰器有时候是很好用的,可以减少代码量,比如在django的视图函数中,如果某个函数必须要登录才能访问,那么就以写一个装饰器来装饰那些函数,
首先说一下如何理解装饰器呢,其实很简单,
1.装装饰器必须是一个可调用对象,用来修饰被装饰的函数,使之增加一些额外功能;
函数就是可调用对象的一种,任何对象只要拥有__call__属性就可以被调用,当然函数自带__call__属性了,
装饰器就一种情况,没有什么多种情况,也没有什么带参数与不带参数之分。
唯一的一种情况就是
def decorator(func):
print('被装饰器的可调用对象:',func)
#开始装饰
def wrapper(*args,**kwargs):
return func(*args,**kwargs)
#返回装饰后的函数
return wrapper
#使用装饰器
@decorator
def a():
print(''hehe)
但是为什么你会看到很多花里胡哨的装饰器呢?,原因很简单,装饰器确实只有上面一种形式是没错的,但是装饰器要求的是最终得到一个可调用对象,那么你可以在最终之前可以干很多事,比如传参, 所以你可以这么去写@decorator(a)(b)(v)(d)(e)...你只要确保最终执行的结果返回的是一个可以接收被装饰函数参数的可调用对象即可,这就意味着,你可以发挥你的想象力想怎么写就怎么写,也许你可以把装饰器写成一个类,然后以@decorator(*args)初始化一个可调用的实例去用,也许你可以写成一个元类,然后直接调用元类创造的类,你也可以函数里套函数,都行,关键在于你的想法和爱好。
直接看一个例子(不用理会例子代码的含义,只看形式即可):
'''必须登录的装饰器'''
def required_login(f=None,redirect_url='login',ret_func=None,parameters=()):
if f is None:# @required_login(*args)方式调用,返回一个装饰器函数
def decorator(view_func):#被返回装饰器
@wraps(view_func)
def wrapper(request,*args,**kwargs):
if request.user.is_authenticated:
return view_func(request,*args,**kwargs)
else:
if ret_func is None:
return redirect(redirect_url)
else:
return ret_func(*parameters)
return wrapper
return decorator
else:# @required_login方式调用,返回一个函数对象,这个函数替代了被装饰的函数
@wraps(f)
def f1(request,*args,**kwargs):
if request.user.is_authenticated:
return f(request,*args,**kwargs)
else:
return redirect(redirect_url)
return f1
@required_login # 第一种调用方式
def test(a):
print(a)
执行 test('123')相当于:
ret_func=required_login(test)
ret_func('123')
@required_login(redirect_url='login') # 第二种调用方式
def test01(a):
print(a)
执行test01('123')相当于:
ret_decorator=required_login(redirect_url='login')
ret_func=ret_decorator(test01)
ret_func('123')
这里说明一下@wraps(f)的作用,因为被装饰器装饰的函数在被使用的时候拿到的已经不是原本的函数了,而是装饰器返回的函数对象,也就意味着原函数的信息丢失了,为了解决这个问题可以使用functools 下的 wraps方法 装饰一下 装饰器函数返回的函数,也就是上面看到的,此时装饰器返回的函数对象的信息就变为原函数的信息。其实wraps方法,是将传入函数f的信息封装到一个对象里面,并且这个对象的拥有__call__属性,在__call__这个方法里调用了被装饰的函数,所以你获取该对象的信息你会发现是函数 f 的,而调用该对象则是被装饰器函数的执行结果。这就是python的灵活之处,python是一种灵活的语言,所以你必须以灵活的方式去理解和学习它。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------