如何编写一个永不返回值的Python生成器函数

41 投票
3 回答
20023 浏览
提问于 2025-04-16 19:06

我想写一个Python生成器函数,但这个函数其实什么都不返回。简单来说,它就是一个“无所作为”的占位符,可以被其他代码使用,这些代码可能会调用生成器,但不一定需要从中获取结果。目前我有这样的代码:

def empty_generator():
    # ... do some stuff, but don't yield anything
    if False:
        yield

现在,这个方法可以正常工作,但我在想有没有更简单明了的方式来表达同样的意思,也就是声明一个函数为生成器,即使它从来不返回任何值。我上面用的技巧是,在我的函数里放一个yield语句,尽管这个语句是无法被执行的。

3 个回答

42

这是一个更简短的解决方案:

def empty_generator():
  yield from []
45

另一种方法是

def empty_generator():
    return
    yield

这其实不是“更有表现力”,只是更简短而已。:)

请注意,iter([]) 或者简单的 [] 也可以达到同样的效果。

4

为了让代码更容易读懂和维护,我建议把一些结构放在函数的最上面。所以可以选择:

  1. 你原来的 if False: yield 结构,但把它放到第一行,或者
  2. 使用一个单独的装饰器,把普通函数变成生成器。

(这是假设你并不只是需要一个可以执行某些操作然后返回一个空的可迭代对象的函数。如果是这样,你可以直接用一个普通函数,最后用 return ()return iter(())。)

想象一下,读你代码的人看到:

def name_fitting_what_the_function_does():
    # We need this function to be an empty generator:
    if False: yield

    # that crucial stuff that this function exists to do

把这个放在最上面,能立刻让每个读这个函数的人注意到这个细节,这个细节会影响整个函数的行为和使用方式。

你的函数体有多长?超过几行吗?如果我在最后才发现这个函数是个生成器,我会感到非常愤怒和失望,因为我可能已经花了很多精力在脑海中构建一个基于它是普通函数的模型——生成器中的第一个 yield 应该是立刻就能看到的,尤其是当你甚至不知道要去找它的时候。

而且,如果函数超过几行,放在函数最开头的结构会更让人信任——我可以相信每个看过这个函数的人,肯定都看过它的第一行。这意味着如果那一行有错误或问题,别人更有可能发现它。这样我就可以少担心这个函数可能有问题,但用的方式让问题不明显。

如果你和那些对Python运作非常熟悉的人一起工作,你甚至可以省略那个注释,因为对他们来说,yield 是让Python把函数变成生成器的关键,这个效果和意图都是显而易见的,因为没有其他理由让正确的代码有一个没有执行的 yield

另外,你也可以选择使用装饰器的方式:

@generator_that_yields_nothing
def name_fitting_what_the_function_does():
    # that crucial stuff for which this exists


def generator_that_yields_nothing(wrapped):
    @functools.wraps(wrapped)
    def wrapper_generator():
        if False: yield
        wrapped()
    return wrapper_generator

撰写回答