2012-04-20 89 views
3

这里是问题:如何在python中实现可插拔函数的“菊花链”?

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

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

3)现在,因为我不知道什么算法最好, d喜欢在每个阶段评估最好的实现(例如,LUT可以通过5种方式生成,我想看哪一个是最好的)

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

我想用双链表结构和生成样序列:

myCaptureClass.addDataTreatment(pmCalibrationFactor(选择,pmExponentialFit(选择,pmLUT(OPT))))

其中myCaptureClass是负责数据表达的类,并且它应该(在获取数据之后)触发顶层数据处理模块(pm)。这种处理将首先深入到底层的孩子(LUT),把数据存在,那么中间(expofit),然后顶部(califactors)和数据返回到拍摄,这将数据返回给请求者。

现在,这有几个问题:

1)无处不在网络上有消息称,蟒蛇不应该使用双链表 2)这对我来说非常低效的,因为数据载体是巨大的,因此我更喜欢使用生成器函数的解决方案,但我不确定如何提供类似于插件的机制。

有人可以给我一个提示如何解决这个使用'插件风格'和发电机,所以我不需要处理向量的X兆字节的数据和处理他们'请求',因为使用生成器函数时是正确的?

非常感谢

大卫

的增编问题:

似乎我没有表达自己完全是。因此:数据由插入VME箱的外部硬件卡生成。它们在单块传输中被提取到python元组中,该元组存储在myCaptureClass中。

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

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

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

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

从这个角度来看,它似乎与我想要做的最接近的匹配显示在bukzor的代码中。我宁愿有一个类实现的,而不是功能,但我想这是实现呼叫运营商特定的类,它实现了数据操作的只是一个化妆品的东西....

+0

如果您能给我们输入/输出的一个简单的例子,我们可以给出具体的答案。 – bukzor 2012-04-20 15:39:12

+1

你应该使用一个python列表,你希望在C++中使用一个双向链表。 – bukzor 2012-04-20 16:30:59

回答

0

从获取functional模块的PyPI。它有一个组成功能来组成两个可调用的。有了这个,你可以将功能链接在一起。

这个模块和functool都提供了一个partial函数,用于部分应用。

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

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的数据?

+0

请注意,这是一个列表理解,而不是生成器,但语法当然几乎是相同的。 – Marcin 2012-04-20 15:43:59

+0

'list(... allthatstuff ...)',但当然你是对的。 – quodlibetor 2012-04-20 16:14:25

+0

我不知道你的意思。您的代码已经生成了一个列表。将它传递给列表构造函数会得到第二个(值相同的)列表。 – Marcin 2012-04-20 16:15:39

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] 
+0

我试着修改函数by2来使用类。我创建了类,使用参数数据覆盖'__call__'函数。 'y = 2'被传递给构造函数。 '__call__'使用'yield'作为mul函数。 我虽然那你:创建一个部分函数,​​构造数据空处理管道,然后调用并返回相同的类,但与数据附加到它。最后的'list(pp(..))'命令调用'__iter__'调用每个函数。如果函数是一个类,它应该调用它的'__call__'。BUT出了问题,因为它令人惊讶地期望我的课程能够迭代。哪里不对? – 2012-04-21 21:52:37

+0

完整的来源:http://belohrad.ch/tmp/daisychain.py – 2012-04-21 21:54:07

+0

@DavidBelohrad:请使用[gist](https://gist.github.com/)或[pocoo pastein](http:// paste.pocoo.org/)。这将有助于保留其他读者的内容,并且使我能够轻松回复。 – bukzor 2012-04-22 19:32:45