从生成器中筛选异常

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

Filter on exception from generator

问题

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

我想出了以下的代码:

  1. def yield_or_skip(iter_: Iterable, func: Callable, skip_on_errors: Iterable[Type[Exception]]) -> Iterator:
  2. skip_on_errors = set(skip_on_errors)
  3. for item in iter_:
  4. try:
  5. yield func(item)
  6. except Exception as e:
  7. if type(e) in skip_on_errors:
  8. continue
  9. 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:

  1. def yield_or_skip(iter_: Iterable, func: Callable, skip_on_errors: Iterable[Type[Exception]]) -> Iterator:
  2. skip_on_errors = set(skip_on_errors)
  3. for item in iter_:
  4. try:
  5. yield func(item)
  6. except Exception as e:
  7. if type(e) in skip_on_errors:
  8. continue
  9. 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

  1. from contextlib import suppress
  2. def yield_or_skip(iter_: Iterable, func: Callable, skip_on_errors: Iterable[Type[Exception]]) -> Iterator:
  3. skipper = suppress(*skip_on_errors)
  4. for item in iter_:
  5. with skipper:
  6. yield func(item)

演示:

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

输出 (在线尝试!):

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

Maybe suppress?

  1. from contextlib import suppress
  2. def yield_or_skip(iter_: Iterable, func: Callable, skip_on_errors: Iterable[Type[Exception]]) -> Iterator:
  3. skipper = suppress(*skip_on_errors)
  4. for item in iter_:
  5. with skipper:
  6. yield func(item)

Demo:

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

Output (Attempt This Online!):

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

答案2

得分: 0

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

  1. from more_itertools import map_except
  2. def yield_or_skip(iter_: Iterable, func: Callable, skip_on_errors: Iterable[Type[Exception]]) -> Iterator:
  3. return map_except(func, iter_, *skip_on_errors)

或者调整其源代码:

  1. for item in iterable:
  2. try:
  3. yield function(item)
  4. except exceptions:
  5. pass
英文:

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

  1. from more_itertools import map_except
  2. def yield_or_skip(iter_: Iterable, func: Callable, skip_on_errors: Iterable[Type[Exception]]) -> Iterator:
  3. return map_except(func, iter_, *skip_on_errors)

Or adapt its source code:

  1. for item in iterable:
  2. try:
  3. yield function(item)
  4. except exceptions:
  5. 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:

确定