簡體   English   中英

了解我自己的裝飾器

[英]Understanding my own decorator

我編寫的裝飾器工作正常,但是由於反復試驗,偶然發現了正確的解決方案,而我對裝飾器的不屑一顧的知識告訴我,定義不明確的東西。

案例是我正在模擬Rest Api做一些TDD,而這個Rest是令牌安全性的背后。 因此,在發出任何請求之前,我首先必須獲取我的用戶令牌。 我正在使用httpretty來模擬API。

到目前為止,我必須在每個測試用例中使用register_uri,一個用於模擬/ token資源,另一個用於測試任何其他資源。 但是我發現這很麻煩,因此附帶了一個解決方案,可以編寫一個簡單的裝飾器來模擬/ token,然后只模擬被測試的資源。

這是我目前正在使用的裝飾器...

def activate_security(func):
    def test_case(test_case):
        httpretty.enable()
        uri = 'http://{}:{}/token'.format(HOST, PORT)
        httpretty.register_uri(httpretty.GET, uri,
                               body=dumps({'token': 'dummy_token'}),
                               content_type='application/json')
        test_case()
        httpretty.disable()
    return test_case

這就是所謂的。

@activate_security
@httpretty.activate
def test_case_one(self):
    #Test case here

我必須將test_case參數傳遞給內部函數,因為沒有它就無法正常工作,而test_case是test_case_one方法,我認為它將在func參數中傳遞,但是外部范圍內的func將對象保留在test_case的內存。

不應該將裝飾器的返回值用作func嗎? 如果我這樣做,裝飾器將無法正常工作。 當內部函數傳遞該參數時?

您正在修飾方法,因此生成的包裝器函數需要一個self變量,就像在類中使用普通函數一樣。

唯一不同的是,您為該self參數使用了一個不同的名稱test_case 碰巧的是,該實例是可調用的,並且調用它可以運行測試,因此您實質上是在進行self()再次運行測試。

只需命名參數self並將其傳遞給包裝的函數即可:

def activate_security(func):
    def wrapper(self):
        httpretty.enable()
        uri = 'http://{}:{}/token'.format(HOST, PORT)
        httpretty.register_uri(httpretty.GET, uri,
                               body=dumps({'token': 'dummy_token'}),
                               content_type='application/json')
        func(self)
        httpretty.disable()
    return wrapper

然后wrapper()函數將替換原始的test_case_one函數,並且在運行測試時, wrapper()函數將綁定到測試用例實例,並將作為self傳遞給該實例; 在包裝器中,您只需將self傳遞給未綁定的 func()即可。

出於調試目的,將一些函數屬性從已包裝的函數復制到包裝器通常更好。 @functools.wraps()裝飾器可以為您處理以下詳細信息:

import functools

def activate_security(func):
    @functools.wraps(func)
    def wrapper(self):
        httpretty.enable()
        uri = 'http://{}:{}/token'.format(HOST, PORT)
        httpretty.register_uri(httpretty.GET, uri,
                               body=dumps({'token': 'dummy_token'}),
                               content_type='application/json')
        func(self)
        httpretty.disable()
    return wrapper

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM