Python中装饰器兼容加括号和不加括号的写法详解


Posted in Python onJuly 05, 2017

使用Django的时候,我发现一个很神奇的装饰器: @login_required, 这是控制一个view的权限的,比如一个视图必须登录才可以访问,可以这样用:

@login_required
def my_view(request):
 ...
 return render(...)

同时,如果要达到这样一种效果:如果用户没有登录,那么就把用户重定向到登录界面,可以这样用:

@login_required(login_url='/accounts/login/')
def my_view(request):
 ...
 return render(...)

所以这个装饰器可以带括号写,又可以不带括号写。很神奇有没有。正常的接收参数的装饰器,就算没参数也应该写成@login_required的

好奇去查了一下,在stackoverflow找到一种实现,挺有意思的。先晒出答案:

def doublewrap(f):
 '''
 a decorator decorator, allowing the decorator to be used as:
 @decorator(with, arguments, and=kwargs)
 or
 @decorator
 '''
 @wraps(f)
 def new_dec(*args, **kwargs):
  if len(args) == 1 and len(kwargs) == 0 and callable(args[0]):
   # actual decorated function
   return f(args[0])
  else:
   # decorator arguments
   return lambda realf: f(realf, *args, **kwargs)
 
 return new_dec

使用起来很简单,只要给装饰器用@doublewrap装饰一下,这个装饰器就支持写括号和不写括号两种写法了。

def test_doublewrap():
 from util import doublewrap
 from functools import wraps 
 
 @doublewrap
 def mult(f, factor=2):
  '''multiply a function's return value'''
  @wraps(f)
  def wrap(*args, **kwargs):
   return factor*f(*args,**kwargs)
  return wrap
 
 # try normal
 @mult
 def f(x, y):
  return x + y
 
 # try args
 @mult(3)
 def f2(x, y):
  return x*y
 
 # try kwargs
 @mult(factor=5)
 def f3(x, y):
  return x - y
 
 assert f(2,3) == 10
 assert f2(2,5) == 30
 assert f3(8,1) == 5*7

原理也不难,只有短短不到10行代码。

装饰器我们都知道,是用来处理一个函数,返回一个新的函数的(如果你不理解装饰器,可以看一下这个经典的解释)。

new_func = decorator(func)

我们使用的,就是被装饰器装饰的新函数了。装饰器只是一个语法糖,其实它也是一个函数,给它传入一个函数作为参数,就返回一个新的函数。那么既然装饰器也是一个函数,我们就可以用装饰器装饰这个函数。也就是,“装饰器的装饰器”。

装饰器第一个参数肯定是原函数,如果装饰器可以接收参数的话,要么第一个参数是原函数,后面跟别的参数;要么就只有原函数一个参数。所以,我们这个“装饰器的装饰器”做的事情就是,判断装饰器接收的参数,如果只有一个并且第一个参数是可调用的(callable),那么这就是一个无参数的装饰器(不需要加括号)。如果还有别的参数,就返回一个生成装饰器的函数(decorator_maker)。

装饰器是一个函数。装饰器被装饰过之后,这个装饰器运行之前就会先运行装饰器的装饰器的代码,也就是我们的doublewrapp。然后返回值可能是一个装饰器,也可能是一个装饰器的maker(有参数的装饰器),然后装饰器再执行,装饰原函数。

这里有点绕,因为本来装饰器里面一般就会有三四层函数了,(maker, decorator, wrapper, realfunc),再加上一个装饰器的装饰器,会有点理解困难。如果理解不了,最好不要对着网上的博文(包括本文)企图格物致知了,多去看看代码,多写一写。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

参考资料

How to create a Python decorator that can be used either with or without parameters?

Python 相关文章推荐
Python 深入理解yield
Sep 06 Python
使用Python开发windows GUI程序入门实例
Oct 23 Python
python分析apache访问日志脚本分享
Feb 26 Python
python 打印出所有的对象/模块的属性(实例代码)
Sep 11 Python
微信 用脚本查看是否被微信好友删除
Oct 28 Python
Linux下Pycharm、Anaconda环境配置及使用踩坑
Dec 19 Python
解决安装python3.7.4报错Can''t connect to HTTPS URL because the SSL module is not available
Jul 31 Python
Python实现朴素贝叶斯的学习与分类过程解析
Aug 24 Python
在python Numpy中求向量和矩阵的范数实例
Aug 26 Python
python numpy数组中的复制知识解析
Feb 03 Python
k-means 聚类算法与Python实现代码
Jun 01 Python
python中判断文件结束符的具体方法
Aug 04 Python
利用python模拟sql语句对员工表格进行增删改查
Jul 05 #Python
利用python实现简单的循环购物车功能示例代码
Jul 05 #Python
用python做一个搜索引擎(Pylucene)的实例代码
Jul 05 #Python
Python对象类型及其运算方法(详解)
Jul 05 #Python
python数据预处理之将类别数据转换为数值的方法
Jul 05 #Python
利用Python3分析sitemap.xml并抓取导出全站链接详解
Jul 04 #Python
在django中使用自定义标签实现分页功能
Jul 04 #Python
You might like
php之XML转数组函数的详解
2013/06/07 PHP
php 启动报错如何解决
2014/01/17 PHP
实现在同一方法中获取当前方法中新赋值的session值解决方法
2014/06/26 PHP
Javascript中的isNaN函数使用说明
2011/11/10 Javascript
form.submit()不能提交表单的原因分析
2014/10/23 Javascript
基于jquery实现即时检查格式是否正确的表单
2016/05/06 Javascript
jQuery操作动态生成的内容的方法
2016/05/28 Javascript
javascript之with的使用(阿里云、淘宝使用代码分析)
2016/10/11 Javascript
easyui取消表单实时验证,提交时统一验证的简单实例
2016/11/07 Javascript
详解NodeJs支付宝移动支付签名及验签
2017/01/06 NodeJs
从源码里了解vue中的nextTick的使用
2018/11/22 Javascript
vue权限管理系统的实现代码
2019/01/17 Javascript
JS/jQuery实现超简单的Table表格添加,删除行功能示例
2019/07/31 jQuery
Vue实现手机号、验证码登录(60s禁用倒计时)
2020/12/19 Vue.js
web.py中调用文件夹内模板的方法
2014/08/26 Python
python MySQLdb Windows下安装教程及问题解决方法
2015/05/09 Python
Python实现将DOC文档转换为PDF的方法
2015/07/25 Python
Python二叉树的镜像转换实现方法示例
2019/03/06 Python
python远程连接MySQL数据库
2019/04/19 Python
python如何以表格形式打印输出的方法示例
2019/06/21 Python
Python如何基于rsa模块实现非对称加密与解密
2020/01/03 Python
用Python做一个久坐提醒小助手的示例代码
2020/02/10 Python
pyspark 随机森林的实现
2020/04/24 Python
在 Windows 下搭建高效的 django 开发环境的详细教程
2020/07/27 Python
基于python requests selenium爬取excel vba过程解析
2020/08/12 Python
css3选择器基本介绍
2014/12/15 HTML / CSS
国际书籍零售商:Wordery
2017/11/01 全球购物
家具厂厂长岗位职责
2014/01/01 职场文书
秋季运动会表扬稿
2014/01/16 职场文书
陈欧的广告词
2014/03/18 职场文书
投标授权委托书范文
2014/08/02 职场文书
2014年学校党建工作汇报材料
2014/11/02 职场文书
安全检查汇报材料
2014/12/26 职场文书
房产公证书格式
2015/01/26 职场文书
创业计划书之宠物店
2019/09/19 职场文书
python 标准库原理与用法详解之os.path篇
2021/10/24 Python