Try-clause包含多个语句

时间:2014-09-22 22:49:59

标签: python function variables try-catch statements

假设我有以下函数/方法,它计算了一堆东西,然后设置了很多变量/属性:calc_and_set(obj)。

现在我想做的是用不同的对象多次调用该函数,如果一个或多个失败则根本不应该设置任何东西。

我以为我可以这样做:

try:
  calc_and_set(obj1)
  calc_and_set(obj2)
  calc_and_set(obj3)
except:
  pass

但这显然不起作用。例如,如果在第三次调用函数时发生错误,则第一次和第二次调用已经设置了变量。

任何人都可以想到一种“干净”的方式来做我想做的事吗?我能想到的唯一解决方案是相当难看的解决方法。

3 个答案:

答案 0 :(得分:1)

我在这里看到了几个选项。

一个。有一个“反向功能”,这是强大的。所以,如果

def calc_and_set(obj):
    obj.A = 'a'

def unset(obj):
    if hasattr(obj, 'A'):
        del obj.A

try:
  calc_and_set(obj1)
  calc_and_set(obj2)
except:
  unset(obj1)
  unset(obj2)

请注意,在这种情况下,unset并不关心calc_and_set是否成功完成。

B中。将calc_and_set分隔为try_calc_and_set,测试它是否有效,以及set,它不会抛出错误,只有在所有try_calc_and_set都没有失败时才会被调用。

try:
  try_calc_and_set(obj1)
  try_calc_and_set(obj2)
  calc_and_set(obj1)
  calc_and_set(obj2)
except:
  pass

℃。 (我最喜欢的) - 让calc_and_set返回一个新变量,而不是在适当的位置操作。如果成功,请用新的参考替换原始参考。这可以通过添加copy作为calc_and_set中的第一个语句,然后返回变量来轻松完成。

try:
  obj1_t = calc_and_set(obj1)
  obj2_t = calc_and_set(obj2)
  obj1 = obj1_t
  obj2 = obj2_t
except:
  pass

那个镜子当然是在以下之前保存你的物品:

obj1_c = deepcopy(obj1)
obj2_c = deepcopy(obj2)
try:
  calc_and_set(obj1)
  calc_and_set(obj2)
except:
  obj1 = obj1_c
  obj2 = obj2_c

作为一般性评论(如果这只是一个示例代码,请原谅我) - 没有指定异常类型就没有例外。

答案 1 :(得分:1)

你也可以尝试缓存你想要采取的行动,如果每个人都通过,你可以一次性完成这些行动:

from functools import partial

def do_something (obj, val):
    # magic here

def validate (obj):
    if obj.is_what_you_want(): 
       return partial(do_something, obj, val)
    else: 
       raise ValueError ("unable to process %s" % obj)


instructions = [validate(item) for item in your_list_of_objects]
for each_partial in instructions:
    each_partial()

如果列表标准收集没有任何例外,则只会触发操作。您可以将其包装为异常安全:

try: 
        instructions = [validate(item) for item in your_list_of_objects]
        for each_partial in instructions:
            each_partial()
        print "succeeded"
 except ValueError:
        print "failed"

答案 2 :(得分:-1)

如果没有"内置"这样做的方式,我认为毕竟"最干净"解决方案是将功能分为两部分。像这样:

try:
    res1 = calc(obj1)
    res2 = calc(obj2) 
    res3 = calc(obj3)
except:
    pass
else:
    set(obj1, res1)
    set(obj2, res2)
    set(obj3, res3)