python - 装饰一个发电机

时间:2016-08-11 15:27:20

标签: python generator decorator

我有2个不同版本的功能;它读取一个大文件(我在这里简单一点,读取一个非常小的excel文件)。

Version 1:阅读整个文件并返回行列表
Version 2:借助生成器逐行阅读

我想装饰这两个函数的输出,并根据不同的逻辑在每行的末尾添加一些东西,这就是为什么我认为我需要一个不同的自定义装饰器。然而我无法弄清楚如何在装饰者的帮助下实现它?特别是当我有收益而不是回报时。

版本1:

@dec
def readxls():
    fileBook = xlrd.open_workbook('../decorator.xls')
    sh = fileBook.sheet_by_name("Sheet1")
    out = []
    for row_index in xrange(1, sh.nrows):
        out.append(sh.row_values(row_index))
    return out

第2版:

@dec2
def readxls():
    fileBook = xlrd.open_workbook('../decorator.xls')
    sh = fileBook.sheet_by_name("Sheet1")
    for row_index in xrange(1, sh.nrows):
        yield sh.row_values(row_index)

让我们说excel文件就像:

Col1    Col2    Col3
Val11   Val12   Val13
Val21   Val22   Val23

我想装饰输出以获得以下结果:

Col1    Col2    Col3   0  Col1Col2
Val11   Val12   Val13  1  Val11Val12
Val21   Val22   Val23  2  Val21Val22

为了得到这样的输出,我的dec1和dec2函数应该如何?

1 个答案:

答案 0 :(得分:1)

装饰器假设使用函数的结果来操作它并给出新结果,因此知道结果是什么是键,在这种情况下,对于该示例,结果是[['val11', 'val12', 'val13'], ['val21', 'val22', 'val23']]版本1和一个发电机,其元件为第二个。有了这些知识,我们可以继续制作一个装饰器,例如

from functools import wraps

def decorator1(fun):
    @wraps(fun)
    def wrapper(*args,**kwds):
        result = fun(*args,**kwds)
        for i,x in enumerate(result,1):
            x.extend( (i, x[0]+x[1]) )
        return result
    return wrapper

def decorator2(fun):
    @wraps(fun)
    def wrapper(*args,**kwds):
        for i,x in enumerate(fun(*args,**kwds),1):
            x.extend( (i, x[0]+x[1]) )
            yield x
    return wrapper

(这里我使用wraps来帮助维护装饰函数的一些元数据(不需要功能)并作为编写示例的指南)

在第一个装饰器中,结果是整个列表,我只是将额外的东西添加到每个元素并返回它,然后在第二个我添加额外的东西,因为它们来维护生成器结构

用这些装饰,结果现在是[['val11', 'val12', 'val13', 1, 'val11val12'], ['val21', 'val22', 'val23', 2, 'val21val22']]

顺便说一下,因为你的2函数做同样的事情,我宁愿保留生成器,当我需要列表调用list(readxls())时,我还要在函数签名中添加2个额外的变量,默认值那些字符串使功能更加灵活。