如何让Python将函数识别为生成器函数? 首先,考虑下面的代码(我将讨论几个版本的子系统)(< /代码>下一步):

如何让Python将函数识别为生成器函数? 首先,考虑下面的代码(我将讨论几个版本的子系统)(< /代码>下一步):,python,generator,yield,Python,Generator,Yield,我想写几个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 *

我想写几个
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
我有一个例外:

maingen started
Traceback (most recent call last):
  ...
TypeError: 'NoneType' object is not iterable
应为:
子发电机2
不是发电机功能

好的,下一个。我可以在某处阅读(如第一个答案) 我必须提出一个
StopIteration
。(请注意,作为一名新手,我无法评论这个答案。)

正如在“最后,该提案还消除了关于如何终止生成器的混淆:正确的方法是
返回
,而不是提出
停止迭代
”,我只得到:

maingen started
(否
maingen已完成
…)

我发现让事情变得好起来的唯一方法是:

>>> def subgen_4(i):
...     i * 3
...     return
...     yield
... 
有了这个,我得到:

maingen started
maingen finished
胡拉!但是这个解决方案并不漂亮

有人有更好的或更像蟒蛇的想法吗?


是否可以编写一个decorator来秘密添加丑陋的yield语句?

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

def subgen_2(i):
    i * 3
    return iter([]) #empty iterator
您得到
TypeError的原因是:如果子生成器中没有
yield
语句,则它不是生成器,而是隐式返回
None
的常规函数

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

另一种隐藏这一点的方法(我真的不明白你为什么想要)是制作一个装饰器,它实际上只是调用你的函数,然后
返回iter(())
从[]
产生

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
回溯(最近一次呼叫最后一次):
文件“/Users/Tadhg/Documents/code/test.py”,第15行,在
对于subgen()中的i:
文件“/Users/Tadhg/Documents/codes/test.py”,第6行,在包装器中
f(*args,**kw)
文件“/Users/Tadhg/Documents/codes/test.py”,第12行,子代
3/0
ZeroDivision错误:被零除

在阅读了所有评论之后,我认为更具python风格的方法是重写
maingen

def maingen(i):
    print("maingen started")
    gen = subgen(i)
    if gen:
        yield from gen
    print("maingen finished")
这样,一个真正是发电机功能的
子发电机

def subgen_1(i):
    yield i + 1
    yield i + 2
    yield i + 3
def subgen_2(i):
    i * 3
或者是一个
子代
,这是一个简单的功能:

def subgen_1(i):
    yield i + 1
    yield i + 2
    yield i + 3
def subgen_2(i):
    i * 3

当在
maingen
generator函数中“注入”时,两者都是“接受的”,并且不需要一些难看的
yield
语句。

a函数可以返回一个生成器,而不必是生成器本身,您只需
返回iter([])
如果您希望函数运行,然后导致一个空迭代器。如果
subgen_2
实际上没有产生任何东西,那么为什么首先使用
yield from subgen_2()
?这个答案链接到您只提到的提出一个
StopIteration
来停止生成器(不首先产生任何东西). 然而,这并没有改变这样一个事实,即你需要在函数体中有一个
yield
语句(语法上),才能使它成为一个生成器函数。使用或使用poke的
yield from[]
,在任何情况下,你都会问如何制作一个与之完全相同的空生成器。因为
返回iter([])
不会将函数本身转换为生成器,您可能更愿意,您可以使用类似于[]的
yield from[]这样的方法来做等效的事情,并生成生成器函数。我要求的是一种更漂亮的方法。。。[]
收益率是个不错的解决方案。但我也在问,是否有可能编写一个装饰程序来隐藏那个“假”陈述……谢谢。我也不是你的粉丝。。。我刚刚发布了一个答案,说明我更喜欢重写
maingen
generator函数。