Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/316.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python @timeout(timelimit)装饰器是如何工作的?_Python - Fatal编程技术网

Python @timeout(timelimit)装饰器是如何工作的?

Python @timeout(timelimit)装饰器是如何工作的?,python,Python,我发现这个修饰符在堆栈溢出上超时了一个函数,我想知道是否有人可以详细解释它是如何工作的,因为代码非常优雅,但一点也不清楚。用法是@timeout(timelimit) @timeout(timelimit)装饰器是如何工作的? 装饰语法 更清楚地说,根据问题中的示例,用法如下: @timeout(100) def foo(arg1, kwarg1=None): '''time this out!''' something_worth_timing_out() def timeo

我发现这个修饰符在堆栈溢出上超时了一个函数,我想知道是否有人可以详细解释它是如何工作的,因为代码非常优雅,但一点也不清楚。用法是
@timeout(timelimit)

@timeout(timelimit)装饰器是如何工作的? 装饰语法 更清楚地说,根据问题中的示例,用法如下:

@timeout(100)
def foo(arg1, kwarg1=None):
    '''time this out!'''
    something_worth_timing_out()
def timeout(seconds=100, error_message=os.strerror(errno.ETIME)):
    def decorator(func):
        def _handle_timeout(signum, frame):
            raise TimeoutError(error_message)
        @wraps(func)
        def wrapper(*args, **kwargs):
            signal.signal(signal.SIGALRM, _handle_timeout)
            signal.alarm(seconds)
            try:
                result = func(*args, **kwargs)
            finally:
                signal.alarm(0)
            return result
        return wrapper
    return decorator
上面是decorator语法。以下内容在语义上是等价的:

def foo(arg1, kwarg1=None):
    '''time this out!'''
    something_worth_timing_out()

foo = timeout(100)(foo)
注意,我们将包装原始foo的函数命名为“
foo
”。这就是decorator语法的含义和作用

必要进口 超时时引发的异常 功能分析 这是一行中的名称,
@timeout(timelimit)
timelimit
参数将被锁定到内部函数中,使这些函数成为“闭包”,之所以称为闭包,是因为它们关闭了数据:

def timeout(seconds=100, error_message=os.strerror(errno.ETIME)):
这将返回一个将函数作为参数的函数,下一行将继续定义该函数。 此函数将返回一个封装原始函数的函数:

    def decorator(func):
这是一个使修饰函数超时的函数:

        def _handle_timeout(signum, frame):
            raise TimeoutError(error_message)
>>> help(foo)
Help on function foo in module __main__:

foo(arg1, kwarg1=None)
    time this out!
这是实际的包装器。在调用wrapped函数之前,它设置一个信号,如果函数没有及时完成并出现异常,则该信号将中断函数:

        def wrapper(*args, **kwargs):
            signal.signal(signal.SIGALRM, _handle_timeout)
            signal.alarm(seconds)
            try:
                result = func(*args, **kwargs)
            finally:
                signal.alarm(0)
如果函数完成,将返回结果:

            return result
这将返回包装器。它确保包装函数从原始函数获取属性,如docstrings、name、函数签名

        return wraps(func)(wrapper)
这就是装饰器从原始调用返回的地方,
@timeout(timelimit)

包装的好处
wrapps函数允许包装目标函数的函数获取该函数的文档,因为
foo
不再指向原始函数:

        def _handle_timeout(signum, frame):
            raise TimeoutError(error_message)
>>> help(foo)
Help on function foo in module __main__:

foo(arg1, kwarg1=None)
    time this out!

更好地使用
包装
为了进一步澄清,wrapps返回一个decorator,其使用方式与此函数非常类似。最好这样写:

@timeout(100)
def foo(arg1, kwarg1=None):
    '''time this out!'''
    something_worth_timing_out()
def timeout(seconds=100, error_message=os.strerror(errno.ETIME)):
    def decorator(func):
        def _handle_timeout(signum, frame):
            raise TimeoutError(error_message)
        @wraps(func)
        def wrapper(*args, **kwargs):
            signal.signal(signal.SIGALRM, _handle_timeout)
            signal.alarm(seconds)
            try:
                result = func(*args, **kwargs)
            finally:
                signal.alarm(0)
            return result
        return wrapper
    return decorator

哦,天哪,不是1而是2个嵌套函数作为一个装饰器的典型,它可以接受参数,也可以不接受参数,这是你必须做的事情,因为装饰器很奇怪(尽管我自己更喜欢functools.partial方法)原始问题,仅供参考。1)python解释器在处理这段代码时实际做了什么?具体来说,它如何执行@timeout(timelimit)指令?2) 返回包装(func)(包装)不清楚。为什么它有两个插入体?3) 为什么try和signal.alarm的组合会产生多个线程,这是执行此函数所必需的?1)请参阅内部函数
包装器
。当您执行
foo()
时,会调用它。2) 见答案末尾的附录。3)
try
与此无关,
最后
如果计时器没有超时,就停止计时器,你必须有一个线程,否则并发性会困难得多。我想我的基本困惑是@decorator(args)做什么。什么是等价的python代码?让我澄清一下,看看答案的开头。谢谢,这非常有帮助。