2012-04-05 83 views
2

我想創建一個新的裝飾器來代替@wraps(f),它可以做任何其他的魔術@wraps(f)。我會怎麼做?擴展functools.wraps裝飾器的功能

具體來說,我有幾個裝飾器的形式爲:

def decorator(f): 
    @wraps(f) 
    def wrapper(*args, **kwargs): 
     # does some stuff in here 
     return f(*args, **kwargs) 
    if not hasattr(wrapper, '_first_line'): 
     wrapper._first_line = inspect.getsourcelines(f)[1] 
    return wrapper 

好像我應該能夠創造這樣一個@wraps_with_first_line(f)裝飾,將盡一切@wraps(f)是因爲這樣做以及if not hasattr(wrapper, '_first_line'): wrapper._first_line = inspect.getsourcelines(f)[1]

回答

1

如果你想添加究竟是不是已經被包裝對象的屬性,那麼你可以使用這個:

def wraps_with_first_line(f): 
    def wrap(wrapper): 
     wrapper = wraps(f)(wrapper) 
     if not hasattr(wrapper, '_first_line'): 
      wrapper._first_line = inspect.getsourcelines(f)[1] 
     return wrapper 
    return wrap 

如果已經被包裝的對象的屬性,使用斯文的方法。

+0

我最終使用了你的答案和Sven的混合體,但它更像你的答案。 – Isaac 2012-04-06 03:02:36

3

您應該更好地添加指向包裝函數的__wrapped__屬性,而不是添加該包裝函數的單個屬性。的functools.wraps()New versions自動做到這一點,但如果你使用Python的是舊版本比3.2,你可以ALS輕鬆地擴展wraps()添加__wrapped__

def my_wraps(wrapped, **kwargs): 
    def decorator(wrapper): 
     functools.update_wrapper(wrapper, wrapped, **kwargs) 
     wrapper.__wrapped__ = wrapped 
    return decorator 

編輯:這裏有一個函數提取原始函數從一個可能的裝飾乘法功能:

def orig_function(f): 
    try: 
     while True: 
      f = f.__wrapped__ 
    except AttributeError: 
     return f 
+0

在我的特殊用例中,我有一些不止一次裝飾/包裝的函數 - 在這些情況下,查看'some_func .__ wrapped__'會將我指向中間包裝,對吧?我可以安全地在我的原始代碼中設置'ifor hasattr ...'來設置'_original_wrapped'或其他類似的東西嗎? (這是否有效地在[agf的答案](http://stackoverflow.com/a/10032158/291280)中完成?) – Isaac 2012-04-05 16:13:26

+0

@Isaac:您也可以編寫一個實用程序函數,通過遵循' __wrapped__'參數。當然,你可以在'decorator()'裏面做任何你想要的。 – 2012-04-05 16:17:14