代码之家  ›  专栏  ›  技术社区  ›  Sylvain Leroux

如何优雅地定义生成空序列的生成器[复制]

  •  1
  • Sylvain Leroux  · 技术社区  · 5 年前

    在python中,通过将yield关键字放在函数体中,可以很容易地定义迭代器函数,例如:

    def gen():
        for i in range(100):
            yield i
    

    我如何定义一个不产生值的生成器函数(生成0个值),以下代码不起作用,因为python不知道它应该是生成器而不是普通函数:

    def empty():
        pass
    

    我可以做点什么

    def empty():
        if False:
            yield None
    

    但那会很难看。有没有什么好的方法来实现一个空的迭代器函数?

    0 回复  |  直到 12 年前
        1
  •  112
  •   senderle    7 年前

    你可以用 return 在生成器中;它停止迭代而不产生任何结果,因此提供了一个显式的替代方案,以使函数超出范围。所以使用 yield 将函数转换为生成器,但在它之前 返回 在产生任何东西之前终止生成器。

    >>> def f():
    ...     return
    ...     yield
    ... 
    >>> list(f())
    []
    

    我不确定它是否比你拥有的好得多--它只是取代了一个不可操作的操作 if 无操作语句 产量 陈述。但它更为地道。注意,使用 产量 不起作用。

    >>> def f():
    ...     yield
    ... 
    >>> list(f())
    [None]
    

    为什么不直接用 iter(()) ?

    这个问题专门问一个空的 发电机功能 . 因此,我认为这是一个关于Python语法内部一致性的问题,而不是一个关于创建空迭代器的最佳方法的问题。

    如果问题实际上是关于创建空迭代器的最佳方法,那么您可能同意 Zectbumo 关于使用 iter() 相反。然而,重要的是要注意到 iter() 不返回函数!它直接返回一个空的iterable。假设您使用的API期望 回报 可接受的。你必须这样做:

    def empty():
        return iter(())
    

    (信用卡应该是 Unutbu 为了给出这个答案的第一个正确版本。)

    现在,你可能会发现上面说得更清楚,但我可以想象在什么情况下它会不那么清楚。考虑一下这个长列表(人为的)生成器函数定义的示例:

    def zeros():
        while True:
            yield 0
    
    def ones():
        while True:
            yield 1
    
    ...
    

    在那长长的名单的末尾,我宁愿看到 产量 在里面,像这样:

    def empty():
        return
        yield
    

    或者,在Python3.3及更高版本中(如 DSM ),这个:

    def empty():
        yield from ()
    

    存在于 产量 keyword一眼就清楚地表明,这只是另一个生成器函数,与所有其他函数一模一样。要花更多的时间才能看到 iter() 版本也在做同样的事情。

    这是一个微妙的区别,但我真的认为 产量 -基于函数的可读性和可维护性更强。

        2
  •  63
  •   Zectbumo    10 年前
    iter(())
    

    你没有 要求 发电机。来吧伙计们!

        3
  •  46
  •   DSM    12 年前

    Python3.3(因为我在 yield from 踢一脚,因为@senderle偷走了我的第一个念头):

    >>> def f():
    ...     yield from ()
    ... 
    >>> list(f())
    []
    

    但我不得不承认,我很难想出一个这样的用例 iter([]) (x)range(0) 不会有同样好的效果。

        4
  •  14
  •   CalculatorFeline Ben Reynwar    8 年前

    另一种选择是:

    (_ for _ in ())
    
        5
  •  6
  •   eddiewould    10 年前

    我更喜欢以下几点:

    def foo():
      raise StopIteration()
      yield
    

    “yield”将其转换为生成器,而Exception表示结果中不包含任何内容(纯空结果)。

        6
  •  4
  •   unutbu    12 年前

    一定是发电机的功能吗?如果没有,怎么样

    def f():
        return iter([])
    
        7
  •  3
  •   Jurjen Bos    9 年前

    生成空迭代器的“标准”方法似乎是iter([])。 我建议将[]设为iter()的默认参数;这已被良好的参数拒绝,请参见 http://bugs.python.org/issue25215 -朱仁

        8
  •  0
  •   user2113422user2113422    10 年前
    generator = (item for item in [])
    
        9
  •  0
  •   Zectbumo    7 年前

    对于那些真正需要函数和生成器的人

    empty = lambda: (_ for _ in ())