在Python中重新运行代码块

在Python中重新运行代码块,python,python-2.7,generator,yield,with-statement,Python,Python 2.7,Generator,Yield,With Statement,我一直在想办法写这样的东西: 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

我一直在想办法写这样的东西:

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不允许您做我想做的事情,因此您只能在函数上使用decorator:(

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

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\u中调用一个函数,而不是像您所做的那样调用两个步进器

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

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
的dict列表必须按顺序匹配。在
all_args
all_kwargs
中的空列表或空dict将使您无法将任何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
             ]
funcs
args
kwargs
的列表不同的是,将它们放在一起可能更容易,就像
zip
-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)

使用重试修饰符--在您希望捕获任何
类型错误的情况下,最多尝试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()
再干净不过了


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

如果方法失败,请使用递归的概念。.仅当发生异常时才递归一次?并运行整个代码块?您能提供一个示例吗?请查看
重试
装饰程序。应该完全满足您的需要。对于处理有时可能失败的web资源非常有用,并且您希望重试放弃前一定次数。-问题是;什么测试表明失败了?代码很简单。这也是一个选项,并且只有在特定的异常情况下才有更干净的重试方式。你也可以编写自己的重试装饰器类作为一个很好的练习。;)已经有了这样的装饰器。。。只有当我将函数调用与args和kwargs一起传入时,这才有效。我真正想做的是传入一段代码,而不仅仅是一个函数。否则,我将不得不继续为我要重新运行的每个代码块声明函数。我是否遗漏了什么,您是否只是将
def
交换
?@BiRico是的,您是对的。使用上下文管理器作为异常处理程序的
将更加优雅。有趣的。。。函数列表如何工作?比如,如果该函数没有args或kwargs呢?或参数,但没有kwargs,反之亦然?对于没有参数的函数,为空列表。我认为一个
所有的_kwargs
都是一个字典列表,可以使用。已经有一个这样的装饰器了。。。无法用with语法将其包装到生成器语句中?生成器不同于上下文管理器(
with
)。小心,别把这里的事情搞混了。你可以用发电机来做,但我不能完全确定。对不起,我搞不清楚到底该怎么称呼它。我现在正在读这两本书。