2010-09-02 45 views
5

雖然我知道你不能直接在裝飾器中引用self,但我想知道是否從args[0]中解決這個問題是不好的做法。我的直覺是,但我想確定。在裝飾器中使用self是不好的做法嗎?

更具體地說,我正在開發一個API到web服務。大約一半的命令需要傳遞一個令牌,以後可以用它來撤消它。我想要的是將該標記設置爲可選參數,如果沒有提供,則生成一個。生成令牌需要對服務器進行經過驗證的調用,該服務器需要來自該對象的數據。

雖然我知道我能做到這一點:

def some_command(self, ..., undo_token = None): 
    if undo_token = None: 
     undo_token = self.get_undo_token() 
    ... 
    return fnord 

我覺得有可能是比有十幾方法相同的代碼更好的辦法。我的想法是寫一個裝飾:

@decorator 
def undoable(fn, *args, **kwargs): 
    if 'undo_token' not in kwargs: 
     kwargs['undo_token'] = args[0].get_undo_token() 
    return (fn(*args, **kwargs), kwargs['undo_token']) 

所以我可以更清晰地寫

@undoable 
def some_command(self, ...): 
    ... 
    return foo 

@undoable 
def some_other_command(self, ...): 
    ... 
    return bar 

難道我自己設置了麻煩向下行?

+0

+1使用裝飾模式實現「撤消」。 – 2010-09-02 22:32:56

+2

裝飾器對裝飾函數的參數有要求沒有任何問題;只要確保它被記錄在案。 – 2010-09-02 23:16:02

回答

6

我不明白你的編碼什麼undoable - 這不是如何裝飾通常是編碼,我不知道該@decorator是來自(有沒有from youforgottotelluswhence import decorator或一些更邪惡知道爲什麼嗎?我無法忍受使用from構建「人造裸露名稱」而不是使用漂亮的裝飾名稱?)。

正常裝飾編碼,如...:

import functools 

def undoable(f): 
    @functools.wraps(f) 
    def wrapper(self, *a, **k): 
     tok = k.get('undo_token') 
     if tok is None: 
      tok = k['undo_token'] = self.get_undo_token() 
     return f(self, *a, **k), tok 
    return wrapper 

但絕對沒有問題的命名包裝的第一,強制性的位置參數self,並且在使用這個,而不是更少的可讀args[0]清晰的多少收穫。

+1

然後查看:http://pypi.python.org/pypi/decorator/2.3。2 – wheaties 2010-09-02 23:09:24

+0

+1「我不能忍受使用'from'來構建'artificial barenames'」 – Pete 2010-09-02 23:21:42

+0

是的,從裝飾器導入裝飾器**真的**確實使Q的代碼無法理解w/oa「參考網址「,就像這樣的」人造裸露名稱「一樣 - 可惜米歇爾選擇在他的文檔中使用它,給用戶這樣一個可怕的例子。進一步可惜的是,至少在這個用例中,第三方裝飾器模塊使得參數變得非常難以遵循,而普通的Python語法將「正在裝飾的函數」從「參數包裝器」整齊地分離出來 - 而不是因爲「簽名保存」而失去黑魔法,而是通過嘲笑他們失去代碼清晰度。 – 2010-09-02 23:21:55

2

裝飾器以通用的方式擴展了它所裝飾的功能的功能。如果裝飾者不對函數做出任何假設,或者它是args或kwargs,它就是最通用的形式,並且可以很容易地用於許多函數。如果你想對傳遞給函數的內容做些什麼,它應該沒問題,但是如果你在裝飾器中使用的底層細節發生了變化,那麼它們的適用性是有限的,並且可能會中斷。

在上面的裝飾器中,如果對象移除了方法get_undo_token(),您還需要重新訪問裝飾器。這樣做很好,但要記錄約束條件,並將該文檔添加到自己的方法文檔中。

只有在絕對必要的情況下才能做到。它用來創建更通用的裝飾器。

相關問題