如何处理列表理解中的异常?

我有一些 Python 的列表内涵,每次迭代都会抛出一个异常。

例如 ,如果我有:

eggs = (1,3,0,3,2)


[1/egg for egg in eggs]

我将在第3个元素中得到一个 ZeroDivisionError异常。

如何处理这个例外情况并继续执行列表内涵?

我能想到的唯一方法是使用 helper 函数:

def spam(egg):
try:
return 1/egg
except ZeroDivisionError:
# handle division by zero error
# leave empty for now
pass

但我觉得这有点麻烦。

在 Python 中有更好的方法吗?

注意: 这是我设计的一个简单示例(参见上面的“ 比如说”) ,因为我的实际示例需要一些上下文。我对避免除零错误并不感兴趣,我感兴趣的是在列表内涵中处理异常。

92809 次浏览

你可以用

[1/egg for egg in eggs if egg != 0]

这将简单地跳过为零的元素。

没有更好的办法了,在很多情况下你可以像 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

由你来决定这是否更麻烦

在 Python 中没有内置的表达式可以让你忽略异常(或者在异常情况下返回备用值 & c) ,所以从字面上讲,“在列表内涵中处理异常”是不可能的,因为列表内涵是一个包含其他表达式的表达式,仅此而已(比如,没有语句,只有语句可以捕获/忽略/处理异常)。

函数调用就是表达式,函数体可以包含所有你想要的语句,所以正如你所注意到的,将容易发生异常的子表达式的求值委托给函数是一个可行的解决方案(其他的,如果可行的话,检查可能引起异常的值,正如其他答案中所建议的那样)。

对于“如何在列表内涵中处理异常”这个问题的正确回答都表达了这个真理的一部分: 1)从字面上,也就是从词汇上理解本身,你做不到; 2)实际上,如果可行的话,你可以将工作委派给一个函数或检查容易出错的值。你一再声称这不是一个答案,因此是毫无根据的。

我知道这个问题已经很老了,但是你也可以创建一个通用函数来简化这个问题:

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]

当然,您可以使默认句柄函数成为任何您想要的(假设您宁愿默认返回“ Nothing”)。

希望这个问题对你或者任何未来的观众有所帮助!

注意: 在 python3中,我将只使用‘ handle’参数关键字,并将其放在参数列表的末尾。这将使得实际的传递参数和诸如此类的通过捕获变得更加自然。

更新(9年后...) : 对于 Python 3,我的意思是切换 *argshandle,这样您就可以指定函数的参数而不需要指定句柄。一个小小的便利:

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]

在 Python2版本中,我们必须在 egg之前传入 handle

我认为一个助手函数,正如提出初始问题的人和 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

输出将是这个 [(1/1, None), (1/3, None), (None, ZeroDivisionError), (1/3, None), (1/2, None)]。有了这个答案,你就可以完全控制自己以任何你想要的方式继续下去。

替代方案 :

def spam2(egg):
try:
return 1/egg
except ZeroDivisionError:
# handle division by zero error
return ZeroDivisionError

是的,错误是返回的,而不是引发的。

我没看到任何回复提到这个。 但是这个示例可以防止对已知的失败案例引发异常。

eggs = (1,3,0,3,2)
[1/egg if egg > 0 else None for egg in eggs]




Output: [1, 0, None, 0, 0]

你可以使用发电机:

def invert(xs):
for x in xs:
try:
yield x
except:
yield None


list(invert(eggs))