接受参数的装饰器
有时,除了装饰的函数之外,装饰器还可以使用参数 。这种技术经常用于函数注册等事情 。一个著名的例子是Pyramid Web应用程序框架中的视图配置 。例如:
@view_config(route_name='home', renderer='templates/mytemplate.pt')def my_view(request): return {'project': 'hello decorators'}假设我们有一个应用程序,用户可以登录并与一个漂亮的gui(图形用户界面)进行交互 。用户与gui的交互触发事件,而这些事件导致Python函数被执行 。让我们假设有很多用户使用这个应用程序,并且他们有许多不同的权限级别 。执行不同的功能需要不同的权限类型 。例如,考虑以下功能:
#这些功能是存在的def current_user_id(): """ 此函数返回当前登录的用户ID,如果没有经过身份验证,则返回None"""def get_permissions(iUserId): """ 返回给定用户的权限字符串列表,例如 ['logged_in','administrator','premium_member'] """#我们需要对这些函数进行权限检查def delete_user(iUserId): """ 删除具有给定ID的用户,只有管理员权限才能访问此函数 """def new_game(): """ 任何已登录的用户都可以启动一个新游戏 """def premium_checkpoint(): """ 保存游戏进程,只允许高级成员访问 """实现这些权限的一种方法是创建多个装饰器,例如:
def requires_admin(fn): def ret_fn(*args,**kwargs): lPermissions = get_permissions(current_user_id()) if 'administrator' in lPermissions: return fn(*args,**kwargs) else: raise Exception("Not allowed") return ret_fndef requires_logged_in(fn): def ret_fn(*args,**kwargs): lPermissions = get_permissions(current_user_id()) if 'logged_in' in lPermissions: return fn(*args,**kwargs) else: raise Exception("Not allowed") return ret_fndef requires_premium_member(fn): def ret_fn(*args,**kwargs): lPermissions = get_permissions(current_user_id()) if 'premium_member' in lPermissions: return fn(*args,**kwargs) else: raise Exception("Not allowed") return ret_fn@requires_admindef delete_user(iUserId): """ 删除具有给定Id的用户,只有具有管理员权限的用户才能访问此函数 """@requires_logged_in def new_game(): """ 任何已登录的用户都可以启动一个新游戏 """@requires_premium_memberdef premium_checkpoint(): """ 保存游戏进程,只允许高级成员访问 """但这太可怕了 。它需要大量的复制粘贴,并且每个装饰器需要不同的名称,如果对权限的检查方式进行了任何更改,则必须更新每个装饰器 。有一个装饰器可以完成这三个工作不是很好吗?
为此,我们需要一个返回装饰器的函数:
def requires_permission(sPermission):def decorator(fn):def decorated(*args,**kwargs):lPermissions = get_permissions(current_user_id())if sPermission in lPermissions:return fn(*args,**kwargs)raise Exception("permission denied")return decoratedreturn decorator def get_permissions(iUserId): #这样装饰器就不会抛出NameError return ['logged_in',]def current_user_id(): #名称错误也是如此 return 1#现在我们可以进行装饰了 @requires_permission('administrator')def delete_user(iUserId): """ 删除具有给定Id的用户,只有具有管理员权限的用户才能访问此函数 """@requires_permission('logged_in')def new_game(): """ 任何已登录的用户都可以启动一个新游戏 """@requires_permission('premium_member')def premium_checkpoint(): """ 保存游戏进程,只允许高级成员访问 """尝试调用delete_user,new_game和premium_checkpoint看看会发生什么 。
premium_checkpoint和delete_user都在消息“权限被拒绝”的情况下引发异常,new_game执行得很好(但没有太多的作用) 。
下面是装饰器的一般形式,带有参数和使用说明:
def outer_decorator(*outer_args,**outer_kwargs):def decorator(fn):def decorated(*args,**kwargs):do_something(*outer_args,**outer_kwargs)return fn(*args,**kwargs)return decoratedreturn decorator @outer_decorator(1,2,3)def foo(a,b,c): print (a) print (b) print (c)foo()这相当于:
def decorator(fn):def decorated(*args,**kwargs):do_something(1,2,3)return fn(*args,**kwargs)return decorated return decorator @decoratordef foo(a,b,c): print (a) print (b) print (c)foo()装饰课程
装饰器不仅限于对函数进行操作,它们也可以对类进行操作 。比方说,我们有一个类可以做很多非常重要的事情,我们想要把它所做的一切都进行计时 。然后我们可以使用time_this像以前一样使用装饰器:
推荐阅读
- 如何用Python操作数据库?
- php加速器之opcache
- 华为NE40E-X16特性,NE40E-X16功能,全业务路由器
- 中国第一个目标飞行器和空间站是
- 出门旅游的三大神器,有人总嫌它们太麻烦,驴友:尽量都带上
- 空调器几种关键零部件介绍
- 净水器产出的水都可以被直接饮用吗?
- 功夫茶器具与标准的功夫茶艺
- 陆羽用的茶器赏析
- 手机边充电边玩,消耗的电量是来自电池还是充电器呢?