【问题标题】:decorating a function that yields装饰一个产生的函数
【发布时间】:2015-01-21 03:51:55
【问题描述】:

是否有可能,如果可以,是否可取,如果可以,推荐使用什么方法来装饰产生值的函数?

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

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

【问题讨论】:

  • 看起来过于复杂。 “装饰产生价值的函数”具体是什么意思?您想到什么用例?
  • @ivan_pozdeev 用例:我有一堆从 api 产生新值的生成器函数。我想在不触及现有功能的情况下应用过滤器。因此,对于一个精简的示例示例def get_new(): result = new_result(); yield result,我只想过滤掉并产生,比如包含字符串 'foobar' 的结果,而不会破坏复杂的new_result 进程

标签: python generator decorator yield python-decorators


【解决方案1】:

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

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 或更高版本,则可以使用 delegation 手动控制包装的生成器,方法是使用 yield from

if flag:
    yield from gen

【讨论】:

    【解决方案2】:

    与其产生每个潜在的返回值,为什么不只产生那些实际存在的?类似

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

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

    【讨论】:

      【解决方案3】:

      对于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
      

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-06-22
          • 2021-04-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-11-17
          • 2021-04-19
          相关资源
          最近更新 更多