[英]How do you create a timeout in a for-loop in Python?
我有一个从 API 检索数据的 for 循环:
app = WebService()
for i in items:
result = app.request(item)
我想创建一个超时,这样,如果app.request
阻塞调用花费太长时间,循环将跳过它,go 到下一个项目。
我已经阅读了一些使用while
循环创建计时器的方法,但我相信在我的情况下,我无法在 for 循环中创建一个while
循环,并使用适用for
for
的continue
子句......那么,我该怎么做做这个?
不幸的是,API 没有提供创建超时的方法。 它不是对 REST API 的 HTTP 调用。
基于这个答案。
这是一个很好的装饰器用例。 当您想要包装具有附加功能的 function 或 class 方法时,装饰器模式很有用。
这相当于如何使用 Python 的signal
库执行 Python 3 超时装饰器。
一旦你有了装饰器,将你的 app.request 包装在一个decorated
过的 function 中,并使用 try-except 处理异常。
# main.py
import signal
DEBUG = True
# Custom exception. In general, it's a good practice.
class TimeoutError(Exception):
def __init__(self, value = "Timed Out"):
self.value = value
def __str__(self):
return repr(self.value)
# This is the decorator itself.
# Read about it here: https://pythonbasics.org/decorators/
# Basically, it's a function that receives another function and a time parameter, i.e. the number of seconds.
# Then, it wraps it so that it raises an error if the function does not
# return a result before `seconds_before_timeout` seconds
def timeout(seconds_before_timeout):
def decorate(f):
if DEBUG: print("[DEBUG]: Defining decorator handler and the new function")
if DEBUG: print(f"[DEBUG]: Received the following function >> `{f.__name__}`")
def handler(signum, frame):
raise TimeoutError()
def new_f(*args, **kwargs):
# Verbatim from Python Docs
# > The signal.signal() function allows defining custom handlers to be executed
# when a signal is received.
if DEBUG: print(f"[DEBUG]: in case of ALARM for function `{f.__name__}`, I'll handle it with the... `handler`")
old = signal.signal(signal.SIGALRM, handler)
# See https://docs.python.org/3/library/signal.html#signal.alarm
if DEBUG: print(f"[DEBUG]: setting an alarm for {seconds_before_timeout} seconds.")
signal.alarm(seconds_before_timeout)
try:
if DEBUG: print(f"[DEBUG]: executing `{f.__name__}`...")
result = f(*args, **kwargs)
finally:
# reinstall the old signal handler
signal.signal(signal.SIGALRM, old)
# Cancel alarm.
# See: https://docs.python.org/3/library/signal.html#signal.alarm
signal.alarm(0)
return result
new_f.__name__ = f.__name__
return new_f
return decorate
import time
@timeout(5)
def mytest():
for i in range(1,10):
interval = 2
if DEBUG: print("[DEBUG]: waiting 2 seconds... on purpose")
time.sleep(interval)
print("%d seconds have passed" % (interval * i))
if __name__ == '__main__':
if DEBUG: print("[DEBUG]: Starting program")
mytest()
您可以在此 repl.it上快速尝试
此外,如果您不想在 function 中“隐藏” API 调用,则可以进行依赖倒置。 也就是说,您装饰的 function 不依赖于任何request
function 实现。 为此,您收到 function 本身作为参数。 见下文:
# simple decoration
@timeout(5)
def make_request(item):
# assuming `app` is defined
return app.request(item)
# dependency inversion
@timeout(5)
def make_request(request_handler, item):
return request_handler(item)
# and then in your loop...
for i in items:
make_request(app.request, item)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.