所以,我定义了一个简单的生成器:
def gen1(x):
if x <= 10:
yield x
for v in gen1(x + 1):
yield v
基本上,我想装饰它,所以它返回所有的值,但是最后一个:
def dec(gen):
def new_gen(x):
g = gen(x)
value = g.next()
for v in g:
yield value
value = v
return new_gen
现在,如果我重新定义gen1
@dec
def gen1(x):
...
for i in gen1(1):
print i # Nothing printed
但如果我使用:
some_gen = dec(gen1)
for i in some_gen(1):
print i # Prints 1 to 9, as needed
为什么我的装饰工作不起作用以及如何解决?
答案 0 :(得分:5)
你的gen1
的递归调用也取决于你的装饰者,所以一切都被装饰者消耗了。
最简单的解决方法是以非递归样式编写生成器,或者封装递归:
@dec
def gen1(x):
def inner(x):
if x <= 10:
yield x
for v in inner(x + 1):
yield v
return inner(x)
@dec
def gen1(x):
for v in range(x, 11):
yield v
答案 1 :(得分:0)
由于装饰器和递归之间的交互,它不起作用。由于您的生成器是递归的,因此它依赖于某种递归关系。通过在生成器和子生成器之间注入修改装饰器,可以打破该重现关系。
只要@dec
删除了最后一个元素,就不能通过单独更改gen1()
使其与@dec
兼容。
但是,您可以更改gen1()
以使其与@dec
兼容:
def dec(gen):
def new_gen(x):
g = gen(x)
value = g.next()
for v in g:
yield value
value = v
return new_gen
@dec
def gen1(x):
def gen2(x):
if x <= 10:
yield x
for v in gen2(x + 1):
yield v
for v in gen2(x):
yield v
for i in gen1(1):
print i # Prints 1 to 9, as needed
这里的诀窍是使gen1()
非递归,并将所有工作委托给另一个未修饰的生成器。后者可以是递归的。
答案 2 :(得分:0)
我必须这样做的解决方案就是在发电机顶部创建发电机!这实际上是装饰电话的想法。所以你这样做,
def funca():
while True:
print "in funca"
yield True
def dec(func):
while True:
print "in funcb"
func.next()
yield True
decfa = dec(funca())
decfa.next()
>>
"in funcb"
"in funca"
至于你的问题(只产生最后一个值)我会做类似的事情:
def funca():
for i in range(1,5):
yield i
def dec2(ff):
try:
while True:
val=ff.next()
except:
yield val
>>>dec2(funca()).next()
4