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

时间:2009-10-06 21:36:06

标签: python exception-handling 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 division by zero error
        # leave empty for now
        pass

但这对我来说有点麻烦。

在Python中有更好的方法吗?

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

8 个答案:

答案 0 :(得分:81)

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

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]

你当然可以随意制作默认的句柄功能(假设你宁愿默认返回'无')。

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

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

答案 1 :(得分:70)

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

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

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

答案 2 :(得分:19)

您可以使用

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

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

答案 3 :(得分:7)

不,没有更好的方法。在很多情况下,你可以像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 :(得分:3)

我认为辅助函数,正如最初提出问题的人和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)]。通过这个答案,您可以完全控制以任何您想要的方式继续。

答案 5 :(得分:1)

我没有看到任何答案提及此。 但是此示例将是一种防止在已知失败案例中引发异常的方法。

#include <stdlib.h>
#include <stdio.h>

struct foo {
    int bar;
};

struct foo* init_foo() {
    struct foo *f = malloc(sizeof(struct foo));
    if (f) {
        f->bar = 5;
        printf("bar0: %d\n", f->bar);
    }
    return f;
}

void free_foo(struct foo* f) {
    free(f);
}

void print_foo(struct foo* f) {
    printf("bar1: %d\n", f->bar);
}

int main() {
    struct foo *f = init_foo(&f);
    if (f) {
        print_foo(f);
        free_foo(f);
    }
}

答案 6 :(得分:0)

您可以使用生成器:

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

list(invert(eggs))

答案 7 :(得分:-1)

我是编程新手,所以只是在想这种方式是否可行...

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


>>> division by zero