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

Nat*_*man 99 python list-comprehension exception

我在Python中有一些列表理解,其中每次迭代都会抛出异常.

例如,如果我有:

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

[1/egg for egg in eggs]
Run Code Online (Sandbox Code Playgroud)

我会ZeroDivisionError在第3个元素中得到一个例外.

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

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

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

但这对我来说看起来有点麻烦.

有没有更好的方法在Python中执行此操作?

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

Bry*_*ead 95

我意识到这个问题已经很老了,但你也可以创建一个通用函数来简化这类事情:

def catch(func, handle=lambda e : e, *args, **kwargs):
    try:
        return func(*args, **kwargs)
    except Exception as e:
        return handle(e)
Run Code Online (Sandbox Code Playgroud)

然后,在你的理解中:

eggs = (1,3,0,3,2)
[catch(lambda : 1/egg) for egg in eggs]
[1, 0, ('integer division or modulo by zero'), 0, 0]
Run Code Online (Sandbox Code Playgroud)

您当然可以根据需要设置默认句柄功能(假设您默认返回'无').

希望这可以帮助您或任何未来的观众提出这个问题!

注意:在python 3中,我只会创建'handle'参数关键字,并将其放在参数列表的末尾.这将使实际传递参数,并通过捕获更加自然.

  • @Bryan,您能否提供“在python 3 中,我只会制作‘handle’参数关键字,并将其放在参数列表的末尾”的代码。尝试将 `handle` 放在 `**kwarg` 之后并得到一个 `SyntaxError`。你的意思是取消引用为`kwargs.get('handle',e)`吗? (5认同)
  • 非常有用,谢谢。虽然我同意理论评论,但这显示了解决我反复遇到的问题的实用方法。 (3认同)
  • 您可能还希望将异常类型作为可选参数(异常类型是否可以参数化?),以便向上抛出意外异常而不是忽略所有异常. (3认同)
  • 给出答案.我建议的一个模式是传递`args`和`kwargs`来处理.这样你可以返回说'egg`而不是硬编码的`0`,或者你正在做的例外. (2认同)
  • @JBCP:更新了我对 Python 3 的答案。其他评论也提供了很好的补充,但保持答案简单。 (2认同)

Ale*_*lli 82

Python中没有内置表达式允许您忽略异常(或者在异常情况下返回备用值和c),因此从字面上讲,"处理列表理解中的异常"是不可能的,因为列表理解是表达式包含其他表达式,仅此而已(即,没有语句,只有语句可以捕获/忽略/处理异常).

函数调用是表达式,函数体可以包含你想要的所有语句,所以如你所知,将容易出错的子表达式的评估委托给一个函数是一种可行的解决方法(其他的,如果可行的话,是检查可能引发异常的值,如其他答案中所建议的那样).

对"如何处理列表理解中的异常"这一问题的正确回答都表达了所有这一事实的一部分:1)字面上,即词汇理解本身,你不能; 2)实际上,您将作业委托给函数或在可行的情况下检查容易出错的值.你一再声称这不是一个答案是没有根据的.

  • 我知道了.所以一个完整的答案是我应该:1.使用函数2.不使用列表理解3.尝试防止异常而不是处理它. (10认同)
  • 我没有看到"不使用列表推导"作为"如何处理列表推导中的异常"的答案的一部分,但我想你可以合理地将其视为"_lexically IN_ LC"的可能后果,它是不可能的处理异常",这确实是字面答案的第一部分. (9认同)

Pet*_*ter 19

您可以使用

[1/egg for egg in eggs if egg != 0]
Run Code Online (Sandbox Code Playgroud)

这将简单地跳过零的元素.

  • 这不回答如何处理列表理解中的异常的问题. (23认同)
  • 嗯,是的,确实如此.它避免了处理异常的需要.是的,它不是一直都是正确的解决方案,但它是一个常见的解决方案. (7认同)
  • 我明白.我收回了评论(虽然我不会删除它,因为那个简短的'讨论'改进了答案). (2认同)

Joh*_*ooy 8

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

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

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
Run Code Online (Sandbox Code Playgroud)

由你来决定是否更麻烦


Elm*_*80s 7

我认为,正如提出最初问题的人和 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
Run Code Online (Sandbox Code Playgroud)

输出将是这个[(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
Run Code Online (Sandbox Code Playgroud)

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


小智 5

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

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


Output: [1, 0, None, 0, 0]
Run Code Online (Sandbox Code Playgroud)