2014-11-04 29 views
1

我從stack_overflow_entry瞭解到,在Python裝飾器中,它們按照它們出現在源代碼中的順序進行應用。根據之前的裝飾器結果,python裝飾器可以被執行還是跳過?

那麼下面的代碼片段應該如何表現呢?

@unittest.skip("Something no longer supported") 
@skipIf(not something_feature_enabled, "Requires extra crunchy cookies to run") 
def test_this(): 
    .... 

第一裝飾(下面說明)請求測試運行到完全跳過test_this()

@unittest.skip("Something no longer supported") 

雖然第二裝飾詢問測試運行跳過運行test_this()有條件。

@skipIf(not something_feature_enabled, "Requires extra crunchy cookies to run")

那麼這是否意味着test_this將不會運行在所有除非我們首先把條件跳轉裝飾?

此外,是否有任何方式在Python中定義相關的裝飾器執行?例如

@skipIf("Something goes wrong") 
@skipIf(not something_feature_enabled, "Requires extra crunchy cookies to run") 
@log 
@send_email 
def test_this(): 
    .... 

的想法是使@log執行和@send_email如果​​是true

道歉,如果我失去了一些非常明顯的東西。

回答

2

我想你可能會錯過一個關鍵點:裝飾器只是一個函數,它傳遞一個函數並返回一個函數。

那麼,這些是相同的:

@log 
def test_this(): 
    pass 

def test_this(): 
    pass 
test_this = log(test_this) 

而且同樣:

@skip("blah") 
def test_this(): 
    pass 

def test_this(): 
    pass 
test_this = skip("blah")(test_this) 

一旦你明白,你所有的問題變得非常簡單。


首先,是的,skip(…)被用來裝飾skipIf(…)(test),所以如果它跳過它裝飾的東西,test將永遠不會被調用。


,並確定在裝飾被調用的順序的辦法是把它們寫在你希望他們調用的順序。

如果你想動態地做到這一點,你應該首先動態地應用裝飾器。例如:

for deco in sorted_list_of_decorators: 
    test = deco(test) 

此外,有沒有在Python任何方式來定義裝飾的依賴性執行?

不,他們都會被執行。與你所要求的更相關,每個裝飾器都被應用到裝飾函數中,而不是裝飾器。

但你永遠只是傳遞一個裝飾的條件裝飾:

def decorate_if(cond, deco): 
    return deco if cond else lambda f: f 

然後:

@skipIf("Something goes wrong") 
@decorate_if(something_feature_enabled, log) 
@decorate_if(something_feature_enabled, send_email) 
def test_this(): 
    pass 

簡單,對不對?

現在,logsend_email修飾符將應用,如果something_feature_enabled是truthy;否則不會以任何方式修飾該函數並只是將其原樣返回的修飾器將會被應用。

但是如果你不能傳遞裝飾器,因爲函數已經裝飾過了?那麼,如果你定義每個裝飾器來展示它所包裝的功能,你可以隨時解開它。如果您始終使用functools.wraps(如果您沒有其他理由,通常應該這樣做 - 即使出於這種原因,您也可以用這種方式輕鬆地進行模擬),則封裝的功能始終可用爲__wrapped__。再次

def undecorate_if(cond): 
    def decorate(f): 
     return f.__unwrapped__ if cond else f 
    return decorate 

而且,如果你想動態做到這一點,你可能要去進行動態裝飾:所以,你可以寫一個裝飾有條件地消除輕鬆裝修的最外層。所以,一個更簡單的解決方案就是跳過你不想要的裝飾器,通過將它們從decos迭代到應用之前。

+0

感謝@abarnert對此進行了詳細說明。 – splintercell 2014-11-05 21:41:21