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

作者:卡瓦邦噶! 时间:2022-08-09 10:46:25 

使用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?

来源:https://www.kawabangga.com/posts/1969

标签:python,装饰器兼容,括号
0
投稿

猜你喜欢

  • 简单掌握Python的Collections模块中counter结构的用法

    2023-05-17 00:20:13
  • asp长文章分页显示思路

    2007-08-23 13:54:00
  • Python人工智能实战之对话机器人的实现

    2021-03-20 15:59:18
  • Array.prototype.slice

    2010-05-07 12:43:00
  • Python类属性与实例属性用法分析

    2022-10-12 03:14:58
  • Python使用scrapy采集数据时为每个请求随机分配user-agent的方法

    2023-02-08 15:20:31
  • js刷新页面方法大全

    2023-08-06 21:05:34
  • Python实现定制自动化业务流量报表周报功能【XlsxWriter模块】

    2022-02-12 01:25:05
  • tensorflow 2.1.0 安装与实战教程(CASIA FACE v5)

    2022-06-12 08:41:23
  • Python如何一行输入多个数,并存入列表

    2023-09-27 19:14:56
  • Python数据分析之 Matplotlib 3D图详情

    2021-03-05 21:20:33
  • ASP编程如何执行存储过程?

    2010-03-17 20:56:00
  • 数据库中聚簇索引与非聚簇索引的区别[图文]

    2012-02-25 19:38:23
  • python爬取酷狗音乐排行榜

    2021-01-24 19:43:49
  • Python中列表的基本操作汇总

    2021-08-20 23:21:27
  • Python为人脸照片添加口罩实战

    2021-11-12 23:39:33
  • python为Django项目上的每个应用程序创建不同的自定义404页面(最佳答案)

    2022-07-26 19:08:11
  • python中黄金分割法实现方法

    2022-05-15 01:45:24
  • Highcharts 图表中图例显示状态存储的功能设计详解

    2023-05-30 02:01:09
  • 如何利用python读取图片属性信息

    2023-12-24 00:57:51
  • asp之家 网络编程 m.aspxhome.com