如何在传递参数或匹配条件时使用装饰器装饰函数

how to decorate a function with decorators when a argument is passed or say a condition is matched

这是带参数的简单装饰器:

app.py

from __future__ import print_function
import time

def newdecorator(arg1):
    def benchmarking(funct):
        #The argument is accessible here
        print("this is the value of argument",arg1)
        def timercheck(*args, **kwarg):
            starttime=time.time()
            print("starting time",time.time())
            funct(*args, **kwarg)
            print("TOTAL TIME TAKEN ::",time.time()-starttime)
        return timercheck
    return benchmarking

#passing value to the decorators with arguments
@newdecorator('arg value')
def tara():
    print("hellow testing")

if __name__=="__main__":
    tara()

装饰器工作正常。它用显示开始时间和所用时间的功能来装饰函数。

我想达到的目标: 我的意思是,我希望有条件地实施装饰器。

我将使用 argparse 模块进行参数解析,这不是什么大问题我想知道的是如何使装饰器有条件地工作。

@decorator 语法只是语法糖。在引擎盖下,所发生的只是装饰器以装饰函数作为参数被调用。

因此您可以只定义没有装饰器的函数,然后在满足条件时应用装饰器:

def tara():
    print("hellow testing")

if script_called_with_t_flag:
    tara = newdecorator('arg value')(tara)

您还可以在模块或其他命名空间中使用全局变量,但这可能只有在您还想将此状态用于其他用途时才有用。配置装饰器行为的应用程序设置并不少见。

import time

TIMING_ENABLED = True


def newdecorator():
    def benchmarking(funct):
        def timercheck(*args, **kwarg):
            if TIMING_ENABLED:
                starttime = time.time()
                print("starting time", time.time())
            funct(*args, **kwarg)
            if TIMING_ENABLED:
                print("TOTAL TIME TAKEN ::", time.time() - starttime)
        return timercheck
    return benchmarking

# passing value to the decorators with arguments


@newdecorator()
def tara():
    print("hellow testing")


if __name__ == "__main__":
    TIMING_ENABLED = False
    tara()

将条件检查放在 timercheck 函数中很重要,因为较低的作用域是在模块初始化期间执行的(在执行 main() 之前),我们将没有机会设置TIMING_ENABLED 变量。

如果您只希望这是一件 on/off 的事情,那么@Rawing 的回答就是正确的选择。

由于您不需要此特定装饰器的任何参数,因此您也可以对其进行简化。我们在没有 () 的情况下应用装饰器,并且可以删除一层嵌套。此外,我们将 functools.wraps 装饰器添加到 timecheck,因此此函数看起来像 python 的 tara 函数。 (请参阅 main 中的附加打印)因为装饰器所做的实际上是用 timecheck.

替换 tara 函数
from __future__ import print_function
import time
from functools import wraps

TIMING_ENABLED = True

def newdecorator(funct):
    @wraps(funct)
    def timercheck(*args, **kwarg):
        if TIMING_ENABLED:
            starttime=time.time()
            print("starting time",time.time())
        funct(*args, **kwarg)
        if TIMING_ENABLED:
            print("TOTAL TIME TAKEN ::",time.time()-starttime)
    return timercheck

@newdecorator
def tara():
    """Docs for tara function"""
    print("hellow testing")

if __name__=="__main__":
    TIMING_ENABLED = True
    print(tara.__name__, tara.__doc__)
    tara()

您可以随时删除 @wraps(funct) 行并查看 main 打印出关于 tara 函数的不同内容。

一种方法是仅在使用 -t 调用脚本时有条件地应用装饰器,否则什么也不做:

import time

script_called_with_t = True

def newdecorator(arg1):
    if script_called_with_t:
        def benchmarking(funct):
            #The argument is accessible here
            print("this is the value of argument",arg1)
            def timercheck(*args, **kwarg):
                starttime=time.time()
                print("starting time",time.time())
                funct(*args, **kwarg)
                print("TOTAL TIME TAKEN ::",time.time()-starttime)
            return timercheck
        return benchmarking
    else:
        return lambda funct: funct

#passing value to the decorators with arguments
@newdecorator('arg value')
def tara():
    print("hellow testing")

if __name__ == "__main__":
    TIMING_ENABLED = False
    tara()

您可以将 sys 模块用于 运行 Python 脚本,使用 windows 命令行中的参数

运行 终端中的此代码与 python app.py True 启用装饰器和禁用装饰器 python app.pypython app.py 假

import time
import sys

TIMING_ENABLED = True


def newdecorator():
    def benchmarking(funct):
        def timercheck(*args, **kwarg):
            if TIMING_ENABLED:
                starttime = time.time()
                print("starting time", time.time())
            funct(*args, **kwarg)
            if TIMING_ENABLED:
                print("TOTAL TIME TAKEN ::", time.time()-starttime)
        return timercheck
    return benchmarking

# passing value to the decorators with arguments


@newdecorator()
def tara():
    print("hellow testing")


if __name__ == "__main__":
    TIMING_ENABLED = sys.argv[1]
    tara()