3

superPythonでパイプラインを作成する方法を考えていました。ストリームに対して実行する必要のある一連の変換があり、それを実行するための良い方法は次のようなものだと思いました。

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個のステージがある場合transformData、変更するのは現在のクラスの名前だけであるN個の同一のメソッドがあります。

この定型文を削除する方法はありますか?私はいくつかのことを試みましたが、結果は私がどのように機能するかを完全に理解していなかったことを私に証明しただけでしたsuper

私が欲しかったのは、メソッドのみを定義し、MROで上がるメソッド__transformationを自然に継承し、そのクラスの「メソッド」を呼び出してから、結果に対して「現在のクラス」を呼び出すことでした。子クラスごとに新しい同一のものを定義することは可能ですか、それとも定義する必要がありますか?transformDatatransformData__transformationtransformData


私は、これがパイプラインを実装するための悪い方法であることに同意します。これは、はるかに単純な(そしてより明確な)スキームで行うことができます。これは、コードをあまり変更せずに既存のクラスからパイプラインを取得するために、既存のモデルに対して実行できる最小限の変更だと思いました。私はこれがそれを行うための最良の方法ではないことに同意します。それはトリックであり、トリックは避けるべきです。また、私はそれがどのように機能するかをよりよく理解する方法として考えましたsuper

Buuuut。好奇心から...上記のスキームでtransformData繰り返しなしでそれを行うことは可能ですか?これは本当の疑いです。その中の呼び出しが現在のクラスで呼び出されるように変更されるtransformData方法で継承するトリックはありますか?super

それは非常に不明瞭で、読めない、賢いお尻のトリックになるでしょう。知っている。しかし、それは可能ですか?

4

2 に答える 2

3

パイプラインに継承を使用するのが正しい方法だとは思いません。

代わりに、次のようなものを検討してください。ここでは、「単純な」例とパラメーター化された例を示します (__call__魔法のメソッドを使用するクラスですが、クロージャ関数を返すか、または を介し​​て「JIT」することさえあります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)

そして、これがOOPソリューションです。前のものと比較すると、かなり不器用です。

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 に答える