如何在python中实现可插拔函数的'daisychaining'?

时间:2012-04-20 15:31:28

标签: python

问题在于:

1)假设我有一些测量数据(例如从我的电子产品中读取1Msample),我需要通过处理链处理它们。

2)该处理链由不同的操作组成,可以交换/省略/具有不同的参数。一个典型的例子是获取这些数据,首先通过查找表传递它们,然后进行指数拟合,然后乘以一些校准因子

3)现在,由于我不知道哪种算法最好,我想在每个阶段评估最佳可能的实现(例如,LUT可以通过5种方式生成,我想看看哪一种是最好的)

4)我想菊花链这些函数,我将构建一个包含顶级算法的“类”,并拥有(即指向)子类,包含低级算法。

我正在考虑使用双链表并生成如下序列:

myCaptureClass.addDataTreatment(pmCalibrationFactor(opt,pmExponentialFit(opt,pmLUT(opt))))

其中myCaptureClass是负责数据处理的类,它也应该(在获取数据之后)触发顶级数据处理模块(pm)。这个处理首先深入到底层子(lut),在那里处理数据,然后是中间(expofit),然后是top(califactors)并将数据返回到捕获,这将把数据返回给请求者。

现在这有几个问题:

1)网上到处都说,在python中不应该使用双链表 2)这在我看来非常低效,因为数据向量很大,因此我更喜欢使用生成器函数的解决方案,但我不确定如何提供“插件式”机制。

有人可以给我一个提示如何使用'插件式'和生成器来解决这个问题,这样我就不需要处理X兆字节数据的向量并按需“处理它们”,这在使用生成器函数时是正确的吗?

非常感谢

大卫

问题的附录:

似乎我没有完全表达自己。因此:数据由插入VME包的外部HW卡生成。它们被“取出”到一个块传递给python元组,它存储在myCaptureClass中。

要应用的操作集实际上是在由此元组表示的流数据上。甚至指数拟合也是流操作(它是在每个样本上应用的一组可变状态过滤器)。

我错误地显示的参数'opt'表示,每个数据处理类都有一些附带的配置数据,并修改用于操作数据的方法的行为。

目标是在myCaptureClass中引入一个菊花链类(而不是函数),当用户请求数据时,我们用来将'原始'数据处理成最终形式。

为了“节省”内存资源,我认为使用生成器函数提供数据可能是个好主意。

从这个角度来看,似乎与我想要做的最接近的匹配在bukzor的代码中显示。我更喜欢有一个类实现而不是函数,但我想这只是在特定类中实现调用运算符的一个美妙的东西,它实现了数据操作....

3 个答案:

答案 0 :(得分:1)

这就是我想象你会这样做的。我希望这不完整,因为我不完全理解你的问题陈述。请让我知道我做错了什么:)

class ProcessingPipeline(object):
    def __init__(self, *functions, **kwargs):
        self.functions = functions
        self.data = kwargs.get('data')
    def __call__(self, data):
        return ProcessingPipeline(*self.functions, data=data)
    def __iter__(self):
        data = self.data
        for func in self.functions:
            data = func(data)
        return data

# a few (very simple) operators, of different kinds
class Multiplier(object):
    def __init__(self, by):
        self.by = by
    def __call__(self, data):
        for x in data:
            yield x * self.by

def add(data, y):
    for x in data:
        yield x + y

from functools import partial
by2 = Multiplier(by=2)
sub1 = partial(add, y=-1)
square = lambda data: ( x*x for x in data )

pp = ProcessingPipeline(square, sub1, by2)

print list(pp(range(10)))
print list(pp(range(-3, 4)))

输出:

$ python how-to-implement-daisychaining-of-pluggable-function-in-python.py 
[-2, 0, 6, 16, 30, 48, 70, 96, 126, 160]
[16, 6, 0, -2, 0, 6, 16]

答案 1 :(得分:0)

从pypi获取functional模块。它具有组合两个callables的组合功能。有了它,你可以将功能链接在一起。

该模块和functool都提供了partial功能,用于部分应用。

您可以像生成任何其他函数一样在生成器表达式中使用组合函数。

答案 2 :(得分:0)

我不知道你想要什么,我觉得我应该指出你可以把你想要的任何东西放在列表理解中:

l = [myCaptureClass.addDataTreatment(
          pmCalibrationFactor(opt, pmExponentialFit (opt, pmLUT (opt))))
     for opt in data]

将创建一个已通过组合函数传递的新数据列表。

或者您可以创建一个用于循环的生成器表达式,这不会构造一个全新的列表,它只会创建一个迭代器。我不认为以这种方式做事有任何好处,而不是仅仅处理循环体中的数据,但看起来很有意思:

d = (myCaptureClass.addDataTreatment(
          pmCalibrationFactor(opt, pmExponentialFit (opt, pmLUT (opt))))
     for opt in data)
for thing in d:
    # do something
    pass

opt是数据吗?