如何编写从不产生任何东西的Python生成器函数

Joh*_*nck 28 python yield generator

我想编写一个从未真正产生任何东西的Python生成器函数.基本上它是一个"无所事事"的插件,可以被其他代码用来调用生成器(但并不总是需要它的结果).到目前为止我有这个:

def empty_generator():
    # ... do some stuff, but don't yield anything
    if False:
        yield
Run Code Online (Sandbox Code Playgroud)

现在,这可行,但我想知道是否有更具表现力的方式来说同样的事情,即声明一个函数是一个生成器,即使它从不产生任何值.我上面使用的技巧是在我的函数中显示Python一个yield语句,即使它无法访问.

Sve*_*ach 33

另一种方式是

def empty_generator():
    return
    yield
Run Code Online (Sandbox Code Playgroud)

不是"更具表现力",而是更短.:)

请注意,iter([])或者只是[]也会这样做.

  • 我投票给了iter([]).[]实际上不是迭代器(你不能在它上面调用.next()等) (4认同)
  • @John:请务必添加评论,说明它在做什么!:) (3认同)
  • 请注意,它现在有效:[PEP 380](http://docs.python.org/dev/whatsnew/3.3.html#pep-380-syntax-for-delegating-to-a-subgenerator)。 (3认同)
  • 这很奇怪,因为通常 **return** 和 **yield** 不能一起出现在函数定义代码中。但我注意到,如果 **return** 替换为 **return 25**,则会引发语法错误: _'return' with argument inside generator_ 。所以带参数返回和不带参数返回是有区别的。这实际上有什么区别? (2认同)
  • @eyquem:生成器中的`return`与到达代码末尾的流相同 - 它会使生成器丢弃它的帧并引发`StopIteration`.返回值是没有意义的,就像到达代码末尾的流不返回值一样. (2认同)

Ami*_*ein 16

一个更短的解决方案:

def empty_generator():
  yield from []
Run Code Online (Sandbox Code Playgroud)

  • 如果你想帮助 Python 避免创建空列表的开销,建议使用元组文字 `()` 而不是列表文字 `[]` (取决于 Python 实现的“智能”程度,它可能能够识别出你永远不要使用列表,并相应地优化到它是等价的,但是 `()` 只是由语言保证不可变,并且 `[] 不是 []` 但 `() 是 () 是正常的,也是预期的`,因此,与使 `[]` 接近自由相比,Python 实现使 `()` 有效地自由所需的聪明才智和精力要少得多。) (4认同)
  • Interresting.但是对于Python 3来说. (2认同)

mtr*_*eur 2

为了获得最大的可读性和可维护性,我会优先考虑位于函数顶部的构造。所以要么

  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
Run Code Online (Sandbox Code Playgroud)

将其放在顶部会立即提示该函数的每个读者了解此细节,这会影响整个函数- 影响对该函数的行为和用法的期望和解释。

你的函数体有多长?超过几行?那么作为一名读者,如果我直到最后都没有得到这个函数是一个生成器的提示,我会对作者感到正义的愤怒和谴责,因为我可能会花费大量的精神成本在我的头脑中编织一个基于模型的模型。假设这是一个常规函数 -yield理想情况下,生成器中的第一个函数应该立即可见,即使您甚至不知道要查找它

另外,在长于几行的函数中,函数开头的构造更值得信赖- 我可以相信任何看过函数的人每次查看函数时都可能看到它的第一行。这意味着如果该线错误或损坏,有人会发现它的可能性更高。这意味着我可以不太警惕整个东西实际上已经损坏但以一种使损坏不明显的方式使用的可能性。

如果您正在与非常熟悉 Python 工作原理的人一起工作,您甚至可以省略该注释,因为对于立即记住yieldPython 将函数变成生成器的原因的人来说,很明显,这是效果,可能还有意图,因为正确的代码没有其他原因具有未执行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
Run Code Online (Sandbox Code Playgroud)

  • 十年过去了,但我很欣赏这个深思熟虑的答案! (3认同)