如何在列表推导式中处理异常?
我在Python中有一个列表推导式,每次迭代可能会抛出一个异常。
举个例子,如果我有:
eggs = (1,3,0,3,2)
[1/egg for egg in eggs]
在第三个元素的时候,我会遇到一个ZeroDivisionError
的异常。
我该如何处理这个异常,并继续执行这个列表推导式呢?
我能想到的唯一方法是使用一个辅助函数:
def spam(egg):
try:
return 1/egg
except ZeroDivisionError:
# handle division by zero error
# leave empty for now
pass
但我觉得这样有点麻烦。
在Python中有没有更好的方法呢?
注意: 这是一个简单的例子(见上面的“举个例子”),我编造这个例子是因为我真实的例子需要一些背景。我并不是想避免除以零的错误,而是想在列表推导式中处理异常。
7 个回答
你可以使用
[1/egg for egg in eggs if egg != 0]
这样做会简单地跳过值为零的元素。
我知道这个问题已经很久了,但你可以创建一个通用的函数来让这类事情变得更简单:
def catch(func, handle=lambda e : e, *args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
return handle(e)
然后,在你的理解中:
eggs = (1,3,0,3,2)
[catch(lambda : 1/egg) for egg in eggs]
[1, 0, ('integer division or modulo by zero'), 0, 0]
当然,你可以把默认的处理函数设置成你想要的任何东西(比如你可能更希望默认返回'None')。
注意:在Python 3中,我建议把'handle'这个参数设置为关键字参数,并把它放在参数列表的最后面。这样在通过catch传递参数时会显得更自然。
更新(9年后...):对于Python 3,我的意思是交换*args
和handle
的位置,这样你可以在不指定handle的情况下给函数传递参数。这是一个小小的便利:
def catch(func, *args, handle=lambda e : e, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
return handle(e)
在使用定义好的函数进行理解时,这非常有帮助:
from math import log
eggs = [1,3,0,3,2]
[catch(log, egg) for egg in eggs]
[0.0, 1.0986122886681098, ValueError('math domain error'), 1.0986122886681098, 0.6931471805599453]
在Python 2版本中,我们必须在egg
之前传入handle
。
在Python中,没有内置的表达式可以让你忽略异常(或者在出现异常时返回其他值),所以从字面上说,在列表推导式中“处理异常”是不可能的,因为列表推导式只是包含其他表达式的一个表达式,仅此而已(也就是说,没有语句,而只有语句才能捕获/忽略/处理异常)。
函数调用是表达式,而函数的主体可以包含你想要的所有语句。所以,正如你所注意到的,将可能出错的子表达式的评估委托给一个函数,是一个可行的解决办法(其他的解决办法包括在可能的情况下检查可能引发异常的值,这在其他答案中也有提到)。
对于“如何在列表推导式中处理异常”这个问题,正确的回答都表达了这个真相的一部分:1)从字面上说,也就是在推导式本身中,你是做不到的;2)实际上,你可以把这个工作交给一个函数,或者在可能的情况下检查可能出错的值。因此,你反复声称这不是一个答案的说法是没有根据的。