3

我正在考虑如何使用super在 python 中制作管道。我必须对流进行一系列转换,我认为这样做的好方法是:

class MyBase(object):
    def transformData(self, x):
        return x

class FirstStage(MyBase):

    def transformData(self, x):
        y = super(FirstStage, self).transformData(x)
        return self.__transformation(y)

    def __transformation(self, x):
        return x * x

class SecondStage(FirstStage):

    def transformData(self, x):
        y = super(SecondStage, self).transformData(x)
        return self.__transformation(y)

    def __transformation(self, x):
        return x + 1

它按我的预期工作,但有可能重复。如果我有 N 个阶段,我将有 N 个相同transformData的方法,我唯一改变的是当前类的名称。

有没有办法删除这个样板?我尝试了一些东西,但结果只向我证明我没有完全理解它是如何super工作的。

我想要的是只定义方法__transformation并自然地继承一个transformData将在 MRO 中上升的方法,调用该类的transformData方法,然后__transformation在结果上调用当前类。是否有可能或者我必须transformData为每个子类定义一个新的相同?


我同意这是实施管道的一种糟糕方式。这可以通过更简单(和更清晰)的方案来完成。我认为这是我可以对现有模型进行的最少修改,以便在不过多修改代码的情况下从现有类中获取管道。我同意这不是最好的方法。这将是一个诡计,应该避免诡计。我也认为它是一种更好地理解如何super工作的方式。

布欧特。出于好奇......是否可以在不transformData重复的情况下在上述方案中做到这一点?这是一个真正的疑问。是否有一种技巧可以以将其中的调用更改为在当前类上调用transformData的方式进行继承?super

这将是一个非常不清楚、难以理解、愚蠢的骗局。我知道。但有可能吗?

4

2 回答 2

3

我不认为对管道使用继承是正确的方法。

相反,考虑这样的事情——这里有一个“简单”的例子和一个参数化的例子(一个使用__call__魔法方法的类,但返回一个封闭的函数也可以,或者甚至通过 'JITing' 一个eval)。

def two_power(x):
    return x * x

def add_one(x):
    return x + 1

class CustomTransform(object):
    def __init__(self, multiplier):
        self.multiplier = multiplier

    def __call__(self, value):
        return value * self.multiplier

def transform(data, pipeline):
    for datum in data:
        for transform in pipeline:
            datum = transform(datum)
        yield datum

pipe = (two_power, two_power, add_one, CustomTransform(1.25))
print list(transform([1, 2, 4, 8], pipe))

会输出

[2.5, 21.25, 321.25, 5121.25]
于 2013-01-15T10:39:06.607 回答
2

问题是在这里使用继承在 OOP 方面相当奇怪。在定义类时,你真的需要定义整个转换链吗?

但是这里最好忘记OOP,任务不是OOP。只需定义转换函数:

def get_pipeline(*functions):
    def pipeline(x):
        for f in functions:
            x = f(x)
        return x
    return pipeline

p = get_pipeline(lambda x: x * 2, lambda x: x + 1)

print p(5)

一个更短的版本在这里:

def get_pipeline(*fs):
    return lambda v: reduce(lambda x, f: f(x), fs, v)

p = get_pipeline(lambda x: x * 2, lambda x: x + 1)
print p(5)

这是一个面向对象的解决方案。如果与前一个相比,它是相当笨拙的:

class Transform(object):
    def __init__(self, prev=None):
        self.prev_transform = prev

    def transformation(self, x):
        raise Exception("Not implemented")

    def transformData(self, x):
        if self.prev_transform:
            x = self.prev_transform.transformData(x)
        return self.transformation(x)

class TransformAdd1(Transform):
    def transformation(self, x):
        return x + 1

class TransformMul2(Transform):
    def transformation(self, x):
        return x * 2

t = TransformAdd1(TransformMul2())
print t.transformData(1) # 1 * 2 + 1
于 2013-01-15T10:52:56.010 回答