2009-10-06 95 views
59

我有一些Python中的列表理解,其中每个迭代都可以抛出异常。如何处理Python中的列表理解中的异常?

例如,如果我有:

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

[1/egg for egg in eggs] 

我会在第三元素的ZeroDivisionError例外。

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

我能想到的唯一方法是使用一个辅助功能:

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

但是,这看起来有点麻烦给我。

有没有更好的方法在Python中做到这一点?

注:这是一个简单的例子(见“例如”以上),我做作,因为我的真实的例子,需要一些背景。我对避免被零错误除法,但是在处理列表理解中的异常方面并不感兴趣。

+2

有一个[PEP 463](https://www.python.org/dev/peps/pep-0463/)添加表达式来处理异常。在你的例子中,它将是'[1 /蛋,除了ZeroDivisionError:无((1,3,0,3,2)]中的蛋。但它仍处于草稿模式。我的直觉是它不会被接受。 Imho表达式可能太乱了(检查多个异常,具有更复杂的组合(多逻辑运算符,复杂的理解等) – cfi 2016-06-06 07:44:21

+1

请注意,对于这个特定的*示例,您可以在np中使用具有适当设置的numpy'ndarray'。这会导致'1/0 = nan',但是我意识到这并不能推广到其他需要这种情况的场合 – gerrit 2016-07-25 19:00:23

回答

55

有没有可以用回避Python中的内置表达式允许您忽略异常(或者在异常情况下返回替代值& c),所以从字面上来说,“处理列表理解中的异常”是不可能的,因为列表理解是一个包含其他表达,仅此而已(即,没有语句,并且只有语句可以捕获/忽略/处理异常)。您可能已经注意到,将异常倾向子表达式的评估委托给一个函数是一种可行的解决方法(其他的,在可行的情况下,检查可能引发异常的值,正如其他答案中所建议的那样)。

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

+6

我明白了。所以一个完整的答案应该是我应该:1.使用函数2.不使用列表理解3.尝试防止异常而不是处理它。 – 2009-10-06 22:15:32

+8

我没有看到“不使用列表解析”作为“如何处理列表解析中的异常”的答案的一部分,但我想你可以合理地将它看作是“可能的结果”,这是不可能的处理例外“,这实际上是字面答复的第一部分。 – 2009-10-06 22:26:50

+0

你能捕捉到一个生成器表达式或生成器理解中的错误吗? – Steve 2017-07-05 22:51:33

18

您可以使用

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

这将直接跳过相应为零的元素。

+10

这并不回答如何在列表理解中处理异常的问题 – 2009-10-06 21:52:46

+4

嗯,是的,它的确如此,它避免了处理异常的需要,是的,它并不是一直适用的解决方案,但它是一种常见的解决方案。 – Peter 2009-10-06 21:57:16

+1

我明白了,我收回了评论(尽管我不会删除它因为那个简短的'讨论'改进了答案) – 2009-10-06 22:16:30

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 

由你来决定这是否是更麻烦或不

+0

我怎么会在这里使用解析? – 2009-10-06 21:56:32

+0

@Nathan:你不会。gnibbler说:*没有没有更好的方法* – SilentGhost 2009-10-06 22:08:37

+0

对不起......我错过了他的回答中的'不':-) – 2009-10-06 22:13:35

58

我意识到这个问题是很老,但你也可以创建一个通用功能,使这种比较容易的事情:

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'参数关键字,并将其放在参数列表的末尾。这会使得实际上通过争论变得更加自然。

+1

非常有用,谢谢。虽然我同意这些理论意见,但这显示了解决我一再遇到的问题的实用方法。 – Paul 2016-03-24 13:07:47

+1

给出答案。我建议的一个mod是通过'args'和'kwargs'来处理。这样,你可以返回说'egg'而不是硬编码'0',或者你正在做的异常。 – 2016-09-06 14:59:40

+1

您可能还希望将异常类型作为可选参数(可以异常类型进行参数化?),以便向上抛出意外的异常,而不是忽略所有异常。 – 00prometheus 2017-11-12 15:09:01

1

我认为帮助者函数,正如问初始问题和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)]。有了这个答案,你完全可以以任何你想要的方式继续下去。