Python装饰器学习之兼容加括号与不加括号写法详解

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_38604641/article/details/71056549
本文和大家分享的主要是Python装饰器相关内容,一起来看看吧,希望对大家学习python有所帮助。
  使用Django的时候,我发现一个很神奇的装饰器: @login_required , 这是控制一个 view 的权限的,比如一个视图必须登录才可以访问,可以这样用:
  @login_requireddef 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 utilimport 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),再加上一个装饰器的装饰器,会有点理解困难。如果理解不了,最好不要对着网上的博文(包括本文)企图格物致知了,多去看看代码,多写一写。

来源:网络
展开阅读全文

没有更多推荐了,返回首页