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

Python 如何处理列表理解中的异常?,python,exception,list-comprehension,Python,Exception,List Comprehension,我对Python有一些列表理解,其中每个迭代都可以抛出一个异常 例如,如果我有: eggs = (1,3,0,3,2) [1/egg for egg in eggs] 我将在第3个元素中得到一个ZeroDivisionError异常 如何处理此异常并继续执行列表 我能想到的唯一方法是使用助手函数: def spam(egg): try: return 1/egg except ZeroDivisionError: # handle divisi

我对Python有一些列表理解,其中每个迭代都可以抛出一个异常

例如,如果我有:

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

[1/egg for egg in eggs]
我将在第3个元素中得到一个
ZeroDivisionError
异常

如何处理此异常并继续执行列表

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

def spam(egg):
    try:
        return 1/egg
    except ZeroDivisionError:
        # handle division by zero error
        # leave empty for now
        pass
但这对我来说有点麻烦

在Python中有更好的方法来实现这一点吗

注意:这是一个简单的示例(请参见上面的“示例”),我设计了这个示例,因为我的真实示例需要一些上下文。我不想避免被零除的错误,而是想在列表理解中处理异常。

您可以使用

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

这将跳过零元素。

不,没有更好的方法。在很多情况下,你可以像彼得一样使用回避

你的另一个选择是不使用理解

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]
当然,您可以根据需要设置默认句柄函数(假设您希望在默认情况下返回'None'

希望这能帮助你或这个问题的未来观众


注意:在Python3中,我只使用'handle'参数关键字,并将其放在参数列表的末尾。这将使实际传递参数和此类传递变得更为自然。

我认为一个助手函数,正如提出初始问题的人和Bryan Head所建议的那样,是好的,一点也不麻烦。一行完成所有工作的魔法代码并不总是可能的,因此如果想要避免
for
循环,helper函数是一个完美的解决方案。但是,我会将其修改为以下内容:

# 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,无),(1/3,无),(无,无错误),(1/3,无),(1/2,无)]
。有了这个答案,你就可以完全控制自己以任何方式继续下去

备选方案:


是的,返回了错误,没有引发。

我没有看到任何答案提到这一点。 但这个例子将是防止为已知失败案例引发异常的一种方法

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


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

我是编程新手,所以我在想如果这种方法也能奏效

>>> eggs = (1,3,0,3,2)
>>> try:
>>>     [1/egg for egg in eggs]
>>> except ZeroDivisionError as e:
>>>     print(e)


>>> division by zero

您可以使用生成器:

def反转(xs):
对于xs中的x:
尝试:
产量x
除:
一无所获
列表(反转(鸡蛋))

这并没有回答如何在列表理解中处理异常的问题。嗯,是的,它回答了。它消除了处理异常的需要。是的,这不是所有时候的正确解决方案,但这是一个普通的解决方案。我理解。我收回评论(尽管我不会删除它,因为简短的“讨论”会改进答案)。我在这里如何使用理解?@Nathan:你不会。格尼布勒说:没有比这更好的方法了对不起。。。我错过了他回答中的“不”字:-)我明白了。因此,一个完整的答案应该是:1。使用函数2。不要使用列表3。尽量防止异常,而不是处理异常。我不认为“不使用列表理解”是“如何在列表理解中处理异常”答案的一部分,但我猜您可以合理地将其视为“从词汇上讲,在LC中,不可能处理异常”的可能后果,这确实是字面答案的第一部分。你能捕捉到生成器表达式或生成器理解中的错误吗?@AlexMartelli,在将来的python版本中使用except子句会有那么困难吗<代码>[x[1]用于列表中的x,索引器传递除外]。解释器不能创建一个临时函数来尝试
x[1]
?@Nathan,上面的1,2,3在函数数据流中变成了巨大的麻烦,其中1。人们通常希望通过lambdas内联函数;2.另一种选择是使用大量嵌套for循环,这违反了函数范式,导致代码容易出错;3.这些错误通常是临时的和潜在的复杂数据集,正如拉丁语中的“数据”一词所表示的那样,这些数据集是给定的,因此不容易防止。非常有用,谢谢。虽然我同意理论上的评论,但这显示了一种解决我反复遇到的问题的实用方法。伟大的答案。我建议的一种模式是将
args
kwargs
传递给handle。通过这种方式,您可以返回say
egg
,而不是硬编码的
0
,或者您正在执行的异常。您可能还希望异常类型作为可选参数(异常类型可以参数化吗?),以便向上抛出意外异常,而不是忽略所有异常。@Bryan,
>>> eggs = (1,3,0,3,2)
>>> try:
>>>     [1/egg for egg in eggs]
>>> except ZeroDivisionError as e:
>>>     print(e)


>>> division by zero