装饰产生的功能

时间:2014-11-23 10:14:15

标签: python generator decorator yield python-decorators

是否可行,如果可行,是否可取,如果是,建议的方法是什么来装饰产生值的函数?

例如,考虑一下我编写的这个虚构的例子

def foobar_creator(func):
    def wrapped(**kwargs):
       res = func(**kwargs)
       flag = True
       for k,v in kwargs:
           if res % v == 0:
               flag = False
               yield k
       if flag: 
            yield res
     return wrapped

@foobar_creator
def generic_yielder(**kwargs):
     for i in xrange(sys.maxint):
           yield i

for i in generic_yielder(foo=3, bar=5, foobar=15):
      print i

4 个答案:

答案 0 :(得分:6)

生成器函数在调用时返回迭代器对象。如果你的装饰者本身也是一个生成器,你需要循环覆盖包裹的结果:

def foobar_creator(func):
    def wrapped(**kwargs):
        gen = func(**kwargs)
        flag = True
        for k, v in kwargs:
            if res % v == 0:
                flag = False
                yield k
        if flag:
            for res in gen:
                yield res
    return wrapped

如果您使用的是Python 3.3或更高版本,则可以使用委派来手动控制包装的生成器,方法是使用yield from

if flag:
    yield from gen

答案 1 :(得分:2)

为什么不仅仅产生实际存在的那些?而不是产生每个潜在的返回值?

def wrap(f, arg):
    for x in f(arg):
        yield x

(为清楚起见,省略了实际的装饰器语法,位置和关键字参数的处理等。)

答案 2 :(得分:2)

对于comment42684128中的情况,解决方案非常简单:

(v for v in f(<args>) if filter_condition(v))

作为装饰者:

def yfilter(filter_condition):
   def yfilter_p(f):
       def wrapped(*args,**kwargs):
           return (v for v in f(*args,**kwargs) if filter_condition(v))
       return wrapped
   return yfilter_p

答案 3 :(得分:0)

现有答案不处理产生并返回值的生成器。为此,您需要return (yield from f())

def dec(f):
    def g():
        return (yield from f())
    return g

@dec
def f():
   yield 'val'
   return 'done'