装饰器中添加参数

Posted 千翻娃儿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了装饰器中添加参数相关的知识,希望对你有一定的参考价值。

一个简单场景:我有一个给函数计时的装饰器,现在我想给函数运行的时间添加一个时间偏移量time_lag,该时间偏移量不是常数,想通过把该参数传入装饰器中来实现。

  • 实现方式1:

import time
from functools import wraps
def timer_func(func,time_lag):
   @wraps(func)
   def wer(*args,**kwargs):
       t1=time.time()
       r=func(*args,**kwargs)
       t2=time.time()
       cost=t2-t1+time_lag
       print(\'time cost %s\'%cost)
       return r
   return wer

def func(n:int):
   while n>0:
       n=n-1
   return n
a=timer_func(func,time_lag=10)
a(1000000)

但是这样的实现方式,就无法语法糖@,每次都要通过函数调用来实现,就失去了装饰器简明、方便的特点了。

因此用另一种实现方式,只需要在原有装饰函数外面再嵌套一层外函数,将想传入装饰器的函数传入最外层函数即可,实现方式如下:

  • 实现方式2:

from functools import wraps
import time
def timer(time_lag):

   def decorator(func):
       @wraps(func)
       def wer(*args, **kwargs):
           t1 = time.time()
           r = func(*args, **kwargs)
           t2 = time.time()
           cost = t2 - t1
           res=cost+time_lag
           print(\'time cost %s\' % res)
           return func(*args, **kwargs)#返回函数本身结果
       return wer#返回内函数
   return decorator#返回外函数

def func(n:int):
   \'\'\'
  this is a func test
  :param n:
  :return:
  \'\'\'
   while n>0:
       n=n-1
   return n

>>>a=timer(10)#返回外函数,#传入time_lag=10
>>>print(a)
<function timer.<locals>.decorator at 0x000002027D8E5E50>
>>>b=a(func)#返回内函数
>>>print(b)
<function func at 0x000002027D9434C0>
>>>c=b(999999)#调用内函数返回结果
>>>print(c)
time cost 10.069796323776245
0

上述逐步调用的过程只是为了清晰的展示,该函数看起来复杂,实际上本质思想还是闭包的思想,只是在装饰器外再嵌套了一层外函数。每个外函数返回的是它的下一级内函数。最内层函数返回的是调用函数的结果。该方式还可以通过语法糖简明的调用:

@timer(10)#传入time_lag=10
def func(n:int):

   while n>0:
       n=n-1
   return n
>>>func(99999)
time cost 10.008002042770386

@timer(20)#传入time_lag=20
def func1(n:int):

   while n>0:
       n=n-1
   return n
>>>func1(22222222)
time cost 21.447203874588013

 

  • 创建一个带参数的日志装饰器

创建一个日志装饰器,该日志的输出等级、名称、信息通过传参传入装饰器中

def logged(level,name=None,message=None):

   def decorator(func):
       logname=name if name else func.__module__
       log=logging.getLogger(logname)
       logmsg=message if message else func.__name__

       @wraps(func)
       def wraper(*args,**kwargs):
           log.log(level,message)
           return func(*args,**kwargs)
       return wraper
   return decorator

@logged(logging.DEBUG,\'test_name\')
def func(a):
   return a+1

 

 

以上是关于装饰器中添加参数的主要内容,如果未能解决你的问题,请参考以下文章

Python - 在装饰器中获取原始函数参数

如何将装饰器中的变量传递给装饰函数中的函数参数?

python包装函数在装饰器中接受参数

python_如何修改装饰器中参数?

在nest.js 中,是不是可以在参数装饰器中获取服务实例?

python装饰器中的@wraps