首先,请考虑以下代码(我将在下面讨论几个版本的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
我有一个例外:
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中所述,“最后,该提案还清除了有关如何终止生成器的混淆:正确的方法是return
,而不是提升StopIteration
。 “,我只得到:
maingen started
(没有maingen finished
...)
我发现让事情变得好的唯一方法是:
>>> def subgen_4(i):
... i * 3
... return
... yield
...
有了这个,我得到:
maingen started
maingen finished
Hourrah!但这个解决方案并不美观......
有没有人有更好或更多的pythonic想法?
是否可以编写一个装饰器来秘密添加丑陋的yield语句?
答案 0 :(得分:2)
如果您希望子生成器不产生任何内容,则返回一个空迭代器:
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消息会有更多的噪音:
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
答案 1 :(得分:0)
阅读完所有评论后,我认为更多 pythonic 方式是重写maingen
:
def maingen(i):
print("maingen started")
gen = subgen(i)
if gen:
yield from gen
print("maingen finished")
这样,subgen
实际上是一个生成器函数:
def subgen_1(i):
yield i + 1
yield i + 2
yield i + 3
或subgen
这是一个简单的函数:
def subgen_2(i):
i * 3
在maingen
生成器函数中“注入”时都被“接受”,并且不需要一些丑陋的yield
语句。