问题:如何处理列表推导中的异常?
我在Python中有一些列表理解,其中每次迭代都可能引发异常。
例如,如果我有:
eggs = (1,3,0,3,2)
[1/egg for egg in eggs]
我将ZeroDivisionError
在第3个元素中得到一个exceptions。
如何处理此异常并继续执行列表理解?
我能想到的唯一方法是使用辅助函数:
def spam(egg):
try:
return 1/egg
except ZeroDivisionError:
# handle division by zero error
# leave empty for now
pass
但这对我来说有点麻烦。
有没有更好的方法在Python中执行此操作?
注意: 这是我做的一个简单示例(请参阅上面的“ 例如 ”),因为我的实际示例需要一些上下文。我对避免除以零错误不感兴趣,但对处理列表理解中的异常不感兴趣。
回答 0
Python中没有内置表达式可让您忽略异常(或在异常的情况下返回替代值&c),因此从字面上来讲,“处理列表推导中的异常”是不可能的,因为列表推导是一个表达式包含其他表达式,仅此而已(即,没有语句,只有语句可以捕获/忽略/处理异常)。
函数调用是表达式,函数主体可以包含您想要的所有语句,因此,如您所注意到的,将易于发生异常的子表达式的评估委托给函数是一种可行的解决方法(其他可行时,检查可能引发异常的值,如其他答案中所建议)。
对“如何处理列表理解中的异常”这一问题的正确回答都表达了所有这些事实的一部分:1)从字面上,即从词法上讲,在理解本身中,你不能做到;2)实际上,在可行的情况下,您将作业委派给某个函数或检查易于出错的值。您一再声称这不是一个答案是没有根据的。
回答 1
我意识到这个问题已经很老了,但是您也可以创建一个通用函数来简化这种事情:
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’参数作为关键字,并将其放在参数列表的末尾。这将使实际传递的论点变得更加自然。
回答 2
您可以使用
[1/egg for egg in eggs if egg != 0]
这只会跳过零元素。
回答 3
没有,没有更好的方法。在很多情况下,您可以像Peter一样使用回避
您的另一选择是不使用理解
eggs = (1,3,0,3,2)
result=[]
for egg in eggs:
try:
result.append(egg/0)
except ZeroDivisionError:
# handle division by zero error
# leave empty for now
pass
由您决定是否比较麻烦
回答 4
我认为,正如提出最初问题的人和布莱恩·海德(Bryan Head)所建议的那样,辅助功能很好,一点也不麻烦。单行执行所有工作的魔术代码总是不可能的,因此,如果要避免for
循环,辅助函数是一个完美的解决方案。但是我将其修改为此:
# A modified version of the helper function by the Question starter
def spam(egg):
try:
return 1/egg, None
except ZeroDivisionError as err:
# handle division by zero error
return None, err
输出将是this [(1/1, None), (1/3, None), (None, ZeroDivisionError), (1/3, None), (1/2, None)]
。有了这个答案,您完全可以控制以任何您想要的方式继续。
回答 5
我没有任何答案提及此事。但是此示例将是一种防止在已知失败案例中引发异常的方法。
eggs = (1,3,0,3,2)
[1/egg if egg > 0 else None for egg in eggs]
Output: [1, 0, None, 0, 0]