2013-01-15 50 views
3

我正在考慮如何使用super在python中製作管道。我有一系列的變革,我必須做一個流的,我覺得做一個好辦法是東西的線路:使用super製作管道?

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如何工作的方式。

Buuuut。出於好奇......是否有可能在上述方案中沒有transformData重複?這是一個真正的疑問。有沒有一種方法可以繼承transformData,其方法是將super中的調用更改爲在當前類上調用?

這將是一個非常不清楚,不可讀,聰明的屁股欺騙。我知道。但是有可能嗎?

+0

我不知道如果我理解正確,澄清這一點: 如果你有階段爲(C1)s_beg - >(C2)s_common - >( C3)s_common - >(C4)s_common - >(C5)s_mid - >(C6)s_com_2 - >(C7)s_com_2 - >(C8)s_end 現在如果您的類s_common只在C2中實現一次,那麼s_com_2(只有在C6),那麼你不需要有相同功能的多個副本。當調用沒有在C7中找到func的定義時,它將自動按照層次結構上升,並根據調用嘗試獲取最高級的轉換函數(s_common或s_com_2)。 我不確定是否正確理解問題。 – pranshus

+0

@pranshus似乎有一個你想讓我澄清的具體問題,但不知怎的,文本丟失了。 –

+0

對不起,我完成我的評論之前按回車。 – pranshus

回答

3

我不認爲使用管道繼承是正確的路要走。我們可以考慮類似這樣的事情 - 這裏用「簡單」例子和一個參數化的例子(一個使用__call__魔術方法的類,但是返回一個封閉函數也可以,或者甚至通過eval「JITing」一個方法)。

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

是的,我同意你的意見。這對於一個非常簡單的行爲來說太複雜了。但是我已經有了這些類,另一個原因是,現在我需要實現這個管道行爲。我想我可以這樣做,以避免重寫很多代碼。也許最好重寫它。 :) 也許我也有一個蹩腳的例子... –

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