如何让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函数。