2016-02-11 86 views
3

假設我有其生成調用取決於數是否爲奇數或偶數指定回調路由器功能的功能:重新使用一個全局函數

def odd_even_router(odd, even): 
    def r(n): 
     if n % 2: 
      odd(n) 
     else: 
      even(n) 
    return r 

我也有類裝飾該附加一個類似路由器的方法,命名爲check_number,一類:

def attach_default_router(cls): 
    def route(self, n): 
     if n % 2: 
      self.on_odd(n) 
     else: 
      self.on_even(n) 

    cls.check_number = route 
    return cls 

然後,飾以@attach_default_router一類具有check_number()自動定義,並只實施on_odd()和​​:

​​

如果我想重新使用odd_even_router(),路由器函數發生器,裏面attach_default_router(),我可以這樣做:

def attach_default_router(cls): 
    def route(self, n): 
     r = odd_even_router(self.on_odd, self.on_even) 
     r(n) 

    cls.check_number = route 
    return cls 

然而,不良影響是,每次check_number()變稱爲,生成一個新的(但相同的)路由器功能。因此,這裏是我的問題:我怎麼能重複使用odd_even_router()發生器內attach_default_router()裝飾,但沒有產生的每一次新的路由器的功能?

問題在心臟是:odd_even_router()返回一個函數,它有一個參數,但check_number(),是一個實例方法,需要兩個(第一個是對象的self)。如果我沒有得到self,我還無法生成路由器功能。當我得到self時,我已經在方法中,並且在那裏生成它需要在每次調用方法時生成。

我怎麼能解決這個難題呢?

+0

你有沒有考慮過使用的混入,而不是類裝飾? –

+0

感謝您向我介紹術語「mixin」。看完以後,我會說這只是多重繼承。那麼,我確實考慮過多重繼承,但我有一個(有點不合理的)逆境。在我的情況下,要裝飾的類是所有其他類的擴展,所以我的直覺是避免從一個以上的東西繼承。但是,是的,這是一個選擇。我會牢記這一點。 –

回答

2

你可以,但是你必須在運行時綁定你的oddeven鉤子,這需要你的工廠稍微不同的實現。

這是因爲不僅是你的route功能的全新每次產生的,所以*是oddeven方法。 self.odd創建每次執行一個表達時間的新方法的包裝,因爲functions are descriptors,並正在綁定到實例(self這裏)每次需要時間。

所以,如果你想生成與裝飾類的所有實例使用一個route()功能,您必須然後手動確保約束力仍然發生:

def odd_even_router_method_factory(odd, even): 
    def route(self, n): 
     if n % 2: 
      odd.__get__(self)(n) 
     else: 
      even.__get__(self)(n) 
    return route 

def attach_default_router(cls): 
    route = odd_even_router_method_factory(cls.on_odd, cls.on_even) 
    cls.check_number = route 
    return cls 

需要注意的是Python的仍然會創建一個route方法對象現在。每次訪問instance_of_your_decorated_class.route時,都會通過描述符協議創建一個方法對象。撥打odd.__get__()even.__get__()時會發生同樣的情況。你不妨堅持你原來的版本,併爲每個調用一個新的route()功能,傳遞self.oddself.even,因爲這可能更具可讀性,並保持可用於既作爲方法和功能,您原來odd_even_router()工廠函數。

+0

提醒一下:您忘記了工廠功能中的「返回路線」。謝謝。我想,就像大多數工程問題一樣,沒有「完美」的解決方案,只有折衷。 –

+0

糟糕,添加了返回語句。確實;儘管使用Python進行工程設計對我來說感覺更加有趣:-) –