假设我有以下函数/方法,它计算了一堆东西,然后设置了很多变量/属性:calc_and_set(obj)。
现在我想做的是用不同的对象多次调用该函数,如果一个或多个失败则根本不应该设置任何东西。
我以为我可以这样做:
try:
calc_and_set(obj1)
calc_and_set(obj2)
calc_and_set(obj3)
except:
pass
但这显然不起作用。例如,如果在第三次调用函数时发生错误,则第一次和第二次调用已经设置了变量。
任何人都可以想到一种“干净”的方式来做我想做的事吗?我能想到的唯一解决方案是相当难看的解决方法。
答案 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)