如何处理列表推导式中的异常?

发布于 2024-08-06 16:15:16 字数 602 浏览 1 评论 0原文

我在 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 中是否有更好的方法来做到这一点?

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

I have some a list comprehension in Python in which each iteration can throw an exception.

For instance, if I have:

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

[1/egg for egg in eggs]

I'll get a ZeroDivisionError exception in the 3rd element.

How can I handle this exception and continue execution of the list comprehension?

The only way I can think of is to use a helper function:

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

But this looks a bit cumbersome to me.

Is there a better way to do this in Python?

Note: This is a simple example (see "for instance" above) that I contrived because my real example requires some context. I'm not interested in avoiding divide by zero errors but in handling exceptions in a list comprehension.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

浅黛梨妆こ 2024-08-13 16:15:16

我意识到这个问题已经很老了,但是您也可以创建一个通用函数来使这种事情变得更容易:

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”参数关键字,并将其放在参数列表的末尾。这将使实际传递参数等通过 catch 变得更加自然。

更新(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]

在 Python 2 版本下,我们必须在 egg 之前传入 handle

I realize this question is quite old, but you can also create a general function to make this kind of thing easier:

def catch(func, handle=lambda e : e, *args, **kwargs):
    try:
        return func(*args, **kwargs)
    except Exception as e:
        return handle(e)

Then, in your comprehension:

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

You can of course make the default handle function whatever you want (say you'd rather return 'None' by default).

Note: in python 3, I would make the 'handle' argument keyword only, and put it at the end of the argument list. This would make actually passing arguments and such through catch much more natural.

Update (9 years later...): For Python 3, I just meant switch *args and handle, so you can specify arguments to the function without specifying handle. A minor convenience:

def catch(func, *args, handle=lambda e : e, **kwargs):
    try:
        return func(*args, **kwargs)
    except Exception as e:
        return handle(e)

This is helpful when using a defined function in the comprehension:

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]

Under the Python 2 version, we would've had to pass in handle before the egg.

世界等同你 2024-08-13 16:15:16

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

函数调用是表达式,函数体可以包含您想要的所有语句,因此将容易出现异常的子表达式的计算委托给函数,正如您所注意到的,是一种可行的解决方法(其他可行的方法是检查可能引发异常的值,正如其他答案中所建议的那样)。

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

There is no built-in expression in Python that lets you ignore an exception (or return alternate values &c in case of exceptions), so it's impossible, literally speaking, to "handle exceptions in a list comprehension" because a list comprehension is an expression containing other expression, nothing more (i.e., no statements, and only statements can catch/ignore/handle exceptions).

Function calls are expression, and the function bodies can include all the statements you want, so delegating the evaluation of the exception-prone sub-expression to a function, as you've noticed, is one feasible workaround (others, when feasible, are checks on values that might provoke exceptions, as also suggested in other answers).

The correct responses to the question "how to handle exceptions in a list comprehension" are all expressing part of all of this truth: 1) literally, i.e. lexically IN the comprehension itself, you can't; 2) practically, you delegate the job to a function or check for error prone values when that's feasible. Your repeated claim that this is not an answer is thus unfounded.

两仪 2024-08-13 16:15:16

您可以使用

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

它来简单地跳过零元素。

You can use

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

this will simply skip elements that are zero.

清欢 2024-08-13 16:15:16

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

你的另一个选择是不使用推导式

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

由你来决定这是否更麻烦

No there's not a better way. In a lot of cases you can use avoidance like Peter does

Your other option is to not use comprehensions

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

Up to you to decide whether that is more cumbersome or not

孤芳又自赏 2024-08-13 16:15:16

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

替代

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

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

I think a helper function, as suggested by the one who asks the initial question and Bryan Head as well, is good and not cumbersome at all. A single line of magic code which does all the work is just not always possible so a helper function is a perfect solution if one wants to avoid for loops. However I would modify it to this one:

# 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

The output will be this [(1/1, None), (1/3, None), (None, ZeroDivisionError), (1/3, None), (1/2, None)]. With this answer you are in full control to continue in any way you want.

Alternative:

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

Yes, the error is returned, not raised.

噩梦成真你也成魔 2024-08-13 16:15:16

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

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


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

I didn't see any answer mention this.
But this example would be one way of preventing an exception from being raised for known failing cases.

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


Output: [1, 0, None, 0, 0]
优雅的叶子 2024-08-13 16:15:16

您可以使用生成器:

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

list(invert(eggs))

You can use generators:

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

list(invert(eggs))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文