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代码?让我澄清一下,看看答案的开头。谢谢,这非常有帮助。