python - flask 用户权限修饰器
问题描述
看书发现这段代码有点云里雾里,装饰器有点昏,希望帮我解析下这段代码!!
from functools import wrapsfrom flask import abortfrom flask_login import current_userfrom .models import Permissiondef permission_required(permission): def decorator(f):@wraps(f)def decorated_function(*args, **kwargs): if not current_user.can(permission):abort(403) return f(*args, **kwargs)return decorated_function return decoratordef admin_required(f): return permission_required(Permission.ADMINISTER)(f)
问题解答
回答1:首先你要理解装饰器的原理:
@abcddef f(): pass
实际上与下面的语句等价:
def f(): passf=abcd(f)
我们现在有一个函数abcd,这个函数的本质是:接受另一个函数当做参数,且返回一个函数。(至于返回的函数用来干嘛那就是你的事了)。这时候,abcd仅仅就是个函数而已,还不是修饰器。而由于以下这个需求十分的常见:有一个旧函数,我们又想定义一个新函数,这个新函数大体上功能与旧函数接近,只是多了一点点的新功能,比如打印个日期,判断个权限什么的。那么定义新函数的过程中肯定会调用这个旧函数,然而新函数其实改变不大,旧函数往往也没用了(因为一般我们后面都是用的新函数了),那么为了不让命名空间变得混乱和方便开发,我们可以简单的就用旧函数的名字来表示新函数,也就是在定义完了一个新函数之后,我们把它的名字又变回以前的f,而以前的f就不要了。所以我们可以这样做:定义一个函数abcd,它接受一个函数f,且返回一个新的函数,再把它的返回值(新函数),再赋值给f(python里函数名也可以赋值,成为另一个函数)。这实际上就是我上面的第二段代码做的事情。由于这个需求太过常见,所以python专门为它定义了语法。你不是每次都要f=abcd(f)吗,那你就直接在f的def语句前面加个@abcd得了,也别每次再写后面那句了,不仅麻烦,有时还容易误解。这时候,abcd就成为了装饰器。了解了这个等价关系,你的函数就好理解了:当你在某处使用的时候,是这样的
@permission_required(permission)def old(): pass
等价于
def old(): passold = permission_required(permission)(old)
优先级相同,运算从左到右,首先计算permission_required(permission),它返回decorator是一个函数,这时候变成old = decorator(old)为了满足成为修饰器的要求,这个decorator应当返回一个新函数才行,在这里就是decorated_function,所以原赋值语句变成old = decorated_function。到这里比较清晰了,把一个函数的名字赋值给一个变量(old),所以old就变成了decorated_function这里所定义的函数。过程也就是:
old = permission_required(permission)(old)-> old = decorator(old)-> old = decorated_function回答2:
希望下面代码对你有帮助
from functools import wrapsdef permission_required(permission): '''返回装饰器,装饰器中使用入参 permission ''' def decorator(f):@wraps(f)def decorated_function(*args, **kwargs): if not permission:print ’403’return return f(*args, **kwargs)return decorated_function return decoratordef admin_required_true(f): '''装饰器函数,返回装饰器 ''' return permission_required(True)(f)def admin_required_false(f): '''装饰器函数,返回装饰器 ''' return permission_required(False)(f)@admin_required_truedef foo(): '''使用装饰器 ''' print ’foo’ @admin_required_falsedef bar(): '''使用装饰器 ''' print ’bar’foo()bar()
运行结果:
foo403
相关文章:
1. python - django 里自定义的 login 方法,如何使用 login_required()2. javascript - git clone 下来的项目 想在本地运行 npm run install 报错3. python如何不改动文件的情况下修改文件的 修改日期4. mysql优化 - mysql count(id)查询速度如何优化?5. 主从备份 - 跪求mysql 高可用主从方案6. angular.js - 不适用其他构建工具,怎么搭建angular1项目7. mysql主从 - 请教下mysql 主动-被动模式的双主配置 和 主从配置在应用上有什么区别?8. node.js - node_moduls太多了9. android-studio - Android 动态壁纸LayoutParams问题10. sql语句如何按or排序取出记录
