【问题标题】:Pythonic way to react on empty generators? [duplicate]对空生成器做出反应的 Pythonic 方式? [复制]
【发布时间】:2021-01-07 07:27:22
【问题描述】:

我想为生成器编写一个包装器,它检查生成器是否产生任何东西,并且(例如)如果没有则引发异常。

我会写:

def my_wrapper(input):
    if input is None:
        return

    found = False
    for elem in my_yielding_function(input):
        found = True
        yield elem

    if not found:
        raise MyException("Empty Generator")

有没有更 Pythonic 的方式来做到这一点?

有一个非常similar question,但它已经有 10 多年的历史了——也许事情已经改变了?

上下文

很难解释 - 我正在使用一个给定的 API 函数,它可能不会产生任何结果,但在这种情况下 my 函数与空输入有区别。

【问题讨论】:

  • 您想保留初始生成器(即不使用它)吗?您能否提供一些必要的上下文?
  • 如果可能的话,是的。但如果有办法避免这个丑陋的found 标志,我也会很高兴。在我看来for.. else 应该是为此,但也许还有其他语法结构?
  • 链接问题中的the second answer 有什么问题?似乎以一种非常简短的 Pythonic 方式完全符合您的要求
  • 我的代码示例不够清晰 - my_generator 不是生成器,而是返回生成器的函数。我已经更改了相应的部分。
  • 嗯,我已经在我的问题中添加了这个问题 :) 答案是否定的 - 这就是我问新问题的原因

标签: python python-3.x generator yield


【解决方案1】:

除了避免无用的 for 循环之外,这消除了对标志的需要。您还可以将其调整为装饰器,以使其可以转发调用参数并且仍然可以重用

def check_if_empty_first(gen):
  it = gen() # This is optional, depends if you want to make it reusable, and it you want to call with check_if_empty_first(gen) or check_if_empty_first(gen())
  try:
    yield next(it)
  except StopIteration as e:
    raise MyException("Empty Generator") from e
  yield from it

装饰器版本:

from functools import wraps
def check_if_empty_first(gen):
  @wraps(gen)
  def inner(*args, **kwargs
    it = gen(*args, **kwargs)
    try:
      yield next(it)
    except StopIteration as e:
      raise MyException("Empty Generator") from e
    yield from it
  return inner

【讨论】:

  • 可能也可以用作@decorator
  • 是的,我也想过,我也进行了相应的编辑;)
  • 这比我希望的要复杂得多,但连同来自链接问题的答案,它似乎是一个合法的解决方案 - 它是可重复使用的 :)
  • 装饰器很复杂,因为它是一个装饰器......但第一个非常直接且富有表现力:如果你不能,你尝试产生第一个项目→它是空的。否则,你正常产生剩余的
猜你喜欢
  • 2011-09-23
  • 1970-01-01
  • 1970-01-01
  • 2011-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-10
  • 1970-01-01
相关资源
最近更新 更多