在 Python 中重新运行代码块

Rerun code block in Python

我一直在寻找一种方法来写这样的东西:

code_that_should_not_be_run_again()
with rerun_code_that_may_fail():
  another_method(x)
  run_me_again_if_i_fail(y)
code_that_should_only_be_run_if_above_succeeds()

上面会运行那段代码,并捕获异常,如果被捕获,则再次尝试运行这段代码。这是我想要的更长的版本:

code_that_should_not_be_run_again()
try:
  another_method(x)
  run_me_again_if_i_fail(y)
catch Exception:
  try:
    another_method(x)
    run_me_again_if_i_fail(y)
  catch Exception:
    raise Exception("Couldn't run")
 code_that_should_only_be_run_if_above_succeeds()

我想我可以使用一个生成器,也许可以将生成的内容捕获到一个 lambda 中,然后 运行 它两次,不知何故,但现在确定我如何编写这样的代码。

这在 Python 中可行吗?或者也许可以做类似的事情?

这是我到目前为止尝试过的方法:

from contextlib import contextmanager
@contextmanager
def run_code():
    print 'will run'
    try:
      yield
    except SomeException:
      try:
        yield
      except SomeException:
        raise SomeException('couldn't run')

Edit Python 不会让你做我想做的,所以你只能在函数上使用装饰器:(

我希望有人发布比这更好的解决方案,但我会使用那个方法,也许还有一个装饰器:

def retry_if_fails(fn, exception=Exception, *args, **kwargs):
    try:
        fn(*args, **kwargs)
    except exception:
        fn(*args, **kwargs)  # if this fails again here, the exception bubbles up

当然,问题是您在 retry_if_fails 中只调用了一个函数,而不是像您所做的那样的两步法。

您可以创建一个函数列表,并将其与一个单独的列表列表一起传递给您要处理的每个函数的参数。

def retry_funcs(fns, all_args, all_kwargs, exception=Exception):
    # all_args is a list of lists
    # all_kwargs is a list of dicts
    try:
        for fn, args, kwargs in zip(fns, all_args, all_kwargs):
            fn(*args, **kwargs)
    except exception:
        for fn, args, kwargs in zip(fns, all_args, all_kwargs):
            fn(*args, **kwargs)

在这一个中,args 的列表列表和 kwargs 的字典列表必须按顺序匹配。 all_argsall_kwargs 中的空列表或空字典将使您无法将任何 args 传递给特定函数,或仅传递 args,或仅传递 kwargs,或两者。

fns = [some_func, another_func]
all_args = [['a', 'b'],  # args for some_func
            []           # no args for another_func
           ]
all_kwargs = [{'param': 'something'}, # kwargs for some_func
              {}                      # no kwargs
             ]

而不是 funcsargskwargs 的列表不同,将它们放在一起可能更容易,就像 [=22= 的结果一样]-ing 会是这样,因为无论如何你都会知道调用中的代码:

fns_with_args_and_kwargs = [(some_func, ['a', 'b'], {'param': 'something'}),
                            (another_func, [], {})
                           ]
# and then
for fn, args, kwargs in fns_with_args_and_kwargs:
    fn(*args, **kwargs)

使用重试装饰器 - https://pypi.python.org/pypi/retry/ - 在你想要捕获任何 TypeError 的情况下,最多尝试 3 次,延迟 5 秒:

from retry import retry

@retry(TypeError, tries=3, delay=5)
def code_block_that_may_fail():
    method_1()
    method_2()
    #Some more methods here...

code_block_that_may_fail()

再干净不过了。

此外,您可以使用内置记录器记录失败的尝试(请参阅文档)。