从生成器中筛选异常

huangapple go评论61阅读模式
英文:

Filter on exception from generator

问题

我想要遍历一个生成器/迭代器并将生成的值传递给函数。
这个函数可以返回一个新值,也可以引发错误。
然后我需要返回这个值或者在出现错误时跳过。

我想出了以下的代码:

def yield_or_skip(iter_: Iterable, func: Callable, skip_on_errors: Iterable[Type[Exception]]) -> Iterator:
    skip_on_errors = set(skip_on_errors)
    for item in iter_:
        try:
            yield func(item)
        except Exception as e:
            if type(e) in skip_on_errors:
                continue
            raise

它似乎有效,但我想知道是否有更好的方法?

注意:它必须是一个迭代器/生成器,我不能将结果收集到列表中。

英文:

I would like to iterate over a generator/iterator and pass the value produced to the function.
The function can either return a new value or raise an error.
I then need to return the value or skip on error.

I came up with the following code:

def yield_or_skip(iter_: Iterable, func: Callable, skip_on_errors: Iterable[Type[Exception]]) -> Iterator:
    skip_on_errors = set(skip_on_errors)
    for item in iter_:
        try:
            yield func(item)
        except Exception as e:
            if type(e) in skip_on_errors:
                continue
            raise

It seems to work, but I was wondering if there is a better way to do this?

Note: it has to be an iterator/generator, I can't gather results in a list.

答案1

得分: 1

也许是suppress

from contextlib import suppress

def yield_or_skip(iter_: Iterable, func: Callable, skip_on_errors: Iterable[Type[Exception]]) -> Iterator:
    skipper = suppress(*skip_on_errors)
    for item in iter_:
        with skipper:
            yield func(item)

演示:

for y in yield_or_skip([2, 0, 3], lambda x: 1/x, [ZeroDivisionError]):
    print(y)

print()

for y in yield_or_skip([2,0,3], lambda x: 1/x, [ValueError]):
    print(y)

输出 (在线尝试!):

0.5
0.3333333333333333

0.5
Traceback (most recent call last):
  File "/ATO/code", line 26, in <module>
    for y in yield_or_skip([2,0,3], lambda x: 1/x, [ValueError]):
  File "/ATO/code", line 19, in yield_or_skip
    yield func(item)
  File "/ATO/code", line 26, in <lambda>
    for y in yield_or_skip([2,0,3], lambda x: 1/x, [ValueError]):
ZeroDivisionError: division by zero
英文:

Maybe suppress?

from contextlib import suppress

def yield_or_skip(iter_: Iterable, func: Callable, skip_on_errors: Iterable[Type[Exception]]) -> Iterator:
    skipper = suppress(*skip_on_errors)
    for item in iter_:
        with skipper:
            yield func(item)

Demo:

for y in yield_or_skip([2, 0, 3], lambda x: 1/x, [ZeroDivisionError]):
    print(y)

print()

for y in yield_or_skip([2,0,3], lambda x: 1/x, [ValueError]):
    print(y)

Output (Attempt This Online!):

0.5
0.3333333333333333

0.5
Traceback (most recent call last):
  File "/ATO/code", line 26, in <module>
    for y in yield_or_skip([2,0,3], lambda x: 1/x, [ValueError]):
  File "/ATO/code", line 19, in yield_or_skip
    yield func(item)
  File "/ATO/code", line 26, in <lambda>
    for y in yield_or_skip([2,0,3], lambda x: 1/x, [ValueError]):
ZeroDivisionError: division by zero

答案2

得分: 0

more_itertools.map_except 执行该任务。您可以使用它,或使用它来实现自己的版本(在线尝试!):

from more_itertools import map_except

def yield_or_skip(iter_: Iterable, func: Callable, skip_on_errors: Iterable[Type[Exception]]) -> Iterator:
    return map_except(func, iter_, *skip_on_errors)

或者调整其源代码:

    for item in iterable:
        try:
            yield function(item)
        except exceptions:
            pass
英文:

more_itertools.map_except does that job. You can use it instead, or use it to implement yours (Attempt This Online!):

from more_itertools import map_except

def yield_or_skip(iter_: Iterable, func: Callable, skip_on_errors: Iterable[Type[Exception]]) -> Iterator:
    return map_except(func, iter_, *skip_on_errors)

Or adapt its source code:

    for item in iterable:
        try:
            yield function(item)
        except exceptions:
            pass

huangapple
  • 本文由 发表于 2023年6月2日 07:15:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/76386269.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定