python - 如何让Python将函数识别为生成器函数?

标签 python generator yield

首先,考虑以下代码(接下来我将讨论 subgen() 的几个版本):

>>> def maingen(i):
...    print("maingen started")
...    yield from subgen(i)
...    print("maingen finished")
...
>>> for i in maingen(5):
...     print(i)
...     

我想编写几个 subgen 生成器函数。

正常的是:

>>> def subgen_1(i):
...     yield i + 1
...     yield i + 2
...     yield i + 3

没有问题,输出符合预期:

maingen started
6
7
8
maingen finished

现在,我想要另一个版本的 subgen 它不会产生任何结果...

如果我尝试这样做:

>>> def subgen_2(i):
...     i * 3

我有一个异常(exception):

maingen started
Traceback (most recent call last):
  ...
TypeError: 'NoneType' object is not iterable

预期:subgen_2 不是生成器函数。

好的,下一步。我可以在某个地方阅读(例如第一个答案 here ) 我必须引发 StopIteration。 (请注意,作为新手,我无法评论此答案。)

>>> def subgen_3(i):
...     i * 3
...     raise StopIteration()
...     

PEP 479 中所述,“最后,该提案还消除了有关如何终止生成器的困惑:正确的方法是返回,而不是引发StopIteration。” ,我只得到:

maingen started

(没有maingen完成...)

我发现让事情顺利进行的唯一方法是:

>>> def subgen_4(i):
...     i * 3
...     return
...     yield
... 

有了这个,我得到:

maingen started
maingen finished
万岁!但这个解决方案并不漂亮......

有人有更好或更Python化的想法吗?

是否可以编写一个装饰器来 secret 添加丑陋的yield语句?

最佳答案

如果您希望子生成器不产生任何结果,则返回一个空迭代器:

def subgen_2(i):
    i * 3
    return iter([]) #empty iterator

您获得 TypeError: 'NoneType' object is not iterable 的原因是因为没有 yield在你的子生成器中声明它不是一个生成器,而是一个隐式返回 None 的常规函数​​。 .

通过返回一个不产生任何值的有效迭代器,您将能够yield from subgen_2()没有错误并且不会生成任何附加值。

隐藏这个的另一种方法(我真的不明白你为什么想要这样做)是创建一个装饰器,它实际上只是调用你的函数,然后执行 return iter(())yield from [] .

def gen_nothing(f):
    @functools.wraps(f)
    def wrapper(*args,**kw):
        f(*args,**kw)
        yield from []
    return wrapper

但是这产生的唯一区别是堆栈将需要一个额外的帧用于包装器,这意味着您的回溯消息将有更多的噪音:

Traceback (most recent call last):
  File "/Users/Tadhg/Documents/codes/test.py", line 15, in <module>
    for i in subgen():
  File "/Users/Tadhg/Documents/codes/test.py", line 6, in wrapper
    f(*args,**kw)
  File "/Users/Tadhg/Documents/codes/test.py", line 12, in subgen
    3/0
ZeroDivisionError: division by zero

关于python - 如何让Python将函数识别为生成器函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37303741/

相关文章:

python - 在 Python 中 x==x 是 False 吗?

boost - 将 boost 随机数生成器与 OpenMP 结合使用

scala - Scala 中 for/yield block 的执行顺序

python - Eratosthenes 筛法中的生成器递归跳过步骤

javascript - 有没有一种方法可以在 js 函数上使用 babelJS 并即时生成产量?

python - 为什么 yield 可​​以指数化?

python - python数组的高效移动、稳健尺度估计

python - 使用另一个数据帧的多索引过滤一个数据帧

python 函数不返回列表

python - list(x),其中 x 是一个生成器对象,不表现为所有 next(x) 结果的列表?