在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
)。小心,别把这里的事情搞混了。你可以用发电机来做,但我不能完全确定。对不起,我搞不清楚到底该怎么称呼它。我现在正在读这两本书。