如何用python装饰生成器

如何用python装饰生成器,python,generator,decorator,Python,Generator,Decorator,因此,我定义了一个简单的生成器: def gen1(x): if x <= 10: yield x for v in gen1(x + 1): yield v 现在,如果我重新定义gen1 @dec def gen1(x): ... for i in gen1(1): print i # Nothing printed 但如果我使用: some_gen = dec(gen1) for i in s

因此,我定义了一个简单的生成器:

def gen1(x):
    if x <= 10:
        yield x
        for v in gen1(x + 1):
            yield v
现在,如果我重新定义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

为什么我的decorator不工作以及如何修复它?

您的
gen1
的递归调用也取决于您的decorator,因此所有内容都会被decorator消耗掉

最简单的修复方法是以非递归样式编写生成器,或者封装递归:

封装:
由于装饰器和递归之间的交互,它无法工作。因为生成器是递归的,所以它依赖于某种递归关系。通过在生成器和子生成器之间注入修改修饰符,可以打破这种重复关系

只要
@dec
删除最后一个元素,就无法通过单独更改
@dec
使其与
gen1()兼容

但是,您可以更改
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
def dec(gen):
def新版本(x):
g=发电机(x)
值=g.next()
对于v in g:
收益率
值=v
返回新的_gen
@十二月
def gen1(x):
def gen2(x):

如果x我的解决方案是在发电机的顶部创建一个发电机!这实际上是一个装饰电话的想法。你也是

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

所以我不能修饰递归函数?另外,为什么gen1=dec(gen1)不能工作?
gen1=dec(gen1)
@dec def gen1():…
相同。它重新绑定
gen1
,而不是创建新名称。请参阅我关于递归的更新答案。
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
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