虽然我同意无法使用上下文管理器完成...但可以使用两个上下文管理器来完成!
结果有点尴尬,我还不确定是否赞成自己的代码,但这就是客户端的样子:
with RetryManager(retries=3) as rm:
while rm:
with rm.protect:
print("Attempt
这里有一个明确的while
循环,而且不止一个,而是两个with
语句,这给我的喜好留下了太多错误的机会。
以下是代码:
class RetryManager(object):
""" Context manager that counts attempts to run statements without
exceptions being raised.
- returns True when there should be more attempts
"""
class _RetryProtector(object):
""" Context manager that only raises exceptions if its parent
RetryManager has given up."""
def __init__(self, retry_manager):
self._retry_manager = retry_manager
def __enter__(self):
self._retry_manager._note_try()
return self
def __exit__(self, exc_type, exc_val, traceback):
if exc_type is None:
self._retry_manager._note_success()
else:
pass
return self._retry_manager.is_still_trying()
def __init__(self, retries=1):
self.max_retries = retries
self.attempt_count = 0
self._success = False
self.protect = RetryManager._RetryProtector(self)
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, traceback):
pass
def _note_try(self):
self.attempt_count += 1
def _note_success(self):
self._success = True
def is_still_trying(self):
return not self._success and self.attempt_count < self.max_retries
def __bool__(self):
return self.is_still_trying()
奖励:我知道你不想把工作分成用装饰器包装的单独函数...但是如果你满意,Mozilla 的 redo 包提供了这样的装饰器,所以你不必自己动手。甚至有一个上下文管理器,它有效地充当您的函数的临时装饰器,但它仍然依赖于您可检索的代码被拆分为单个函数。