我想要創建一個新的函數/方法,使得使用對象obj
的裝飾。如果裝飾對象是函數,則在創建函數時必須實例化obj
。如果裝飾對象是一種方法,則必須實例化新的obj
,並將其綁定到方法已裝飾的類的每個實例。我不能把裝修放在__init__
中,因爲修飾者修改了功能文檔。我有這樣的事情了,但它只是實例time
一次,這不是我想要的:具有實例化時間變量的Python裝飾器?
__all__ = ['dec', 'A']
from time import time
import inspect
def dec(f):
obj = time() # want to set on object instantiation
def new(*args, **kwargs):
f(*args, **kwargs) # Validate against definition so it doesn't go
# out of sync
print obj
# ...
try:
d = inspect.getsourcelines(f)
except IOError:
d = "<unable to fetch definition>"
else:
d = d[0][1].rstrip('\n').rstrip(':').lstrip(' ').lstrip('def')
new.__doc__ = d + "\n" + (f.__doc__ or '')
return new
class A(object):
@dec
def f(self, x):
"""something"""
print '%s.f(%s)' % (self, x)
if __name__ == '__main__':
A().f(123)
A().f(123)
A().f(123)
我的想法來解決這個問題就是要檢查是否傳遞給裝飾對象接受一個參數self
如果是這樣,返回結合obj
到self
如果它不是已經存在,然後使用self.obj
的方法。然後,如果沒有self
參數傳遞給裝飾對象,只是實例obj
裝飾內部,並返回一個函數,利用這一點。
不過......我說的並沒有真正爲我工作,因爲我真正的裝飾,我返回從list
衍生並具有__call__
屬性的對象。此外,在實際裝飾,self
甚至沒有在得到由它的裝飾,因爲他們沒有利用自己的實例變量的對象定義(什麼,我真的裝飾只是受到外部物體訂閱事件,事件已經記錄了簽名)。
編輯:其實,如果有一種方法,使一list
子類的實例獲取綁定到一個實例,以便它__call__
屬性隱含接收類實例(如在任何正常的實例方法),這將是一個完美的解決方案,這是我最初試圖找出如何去做的。但也許有更好的解決方案,我不需要用self
屬性定義裝飾方法?要麼是完美的。
我明確表示這不是我想要的。我的裝飾器更改裝飾函數的文檔,如果將裝飾放入'__init__'中,則不會發生這種情況。 – 2010-01-05 17:52:07
@Longpoke:爲什麼'__doc__'如此重要?爲什麼不使用元類來生成'__doc__'的一部分? – 2010-01-05 18:41:29
裝飾器將函數轉換爲list的子類並向其添加__call__。這會破壞'__doc__',所以我將它複製到新創建的對象。我沒有元類的經驗,但我不確定它會在這裏起作用。我已經在使用abc.ABCMeta了,我能一次使用兩個元類嗎?我真正需要的是'__call__'方法(我添加到列表子類)來接收'self',所以我可以保持狀態。 – 2010-01-05 19:08:17