[英]How to call a decorator (instance method) of other class?
我有一個名為RMath()
的 class ,它需要 2 個值a
和b
。 然后是一個名為add()
的 function ,它總結了這些a
和b
。 現在我想記錄計算時間。 我決定在這里使用裝飾器而不觸及原來的 function。 同時,我不想在同一個 class 中編寫這個裝飾器,所以我創建了一個新的 class 作為Handler
,並創建了一個實例方法作為timeit
。 但是當我嘗試將此裝飾器用作@Handler.timeit
時,它會引發錯誤TypeError: timeit() missing 1 required positional argument: 'func'
import time
class Handlers():
def timeit(self, func):
def timefunc():
start = time.time()
func()
end = time.time()
print('Time taken: ', end - start)
return timefunc()
class RMath():
def __init__(self, a, b):
self.a = a
self.b = b
@Handlers.timeit
def add(self):
try:
self.a + self.b
except Exception as e:
return e
a = 10
b = 20
m = RMath(a, b)
c = m.add()
print(c)
至少從錯誤中我可以看到@Handlers.timeit
存在一些問題
有人可以幫我理解這個問題嗎?
即使我將 self 從裝飾器中刪除為def timeit(func):
它會拋出錯誤: TypeError: add() missing 1 required positional argument: 'self'
在這種情況下,您可以使用@classmethod
或@staticmethod
。 這是我的處理方法:
from functools import wraps
from time import time
class Handlers:
@staticmethod
def timeit(func):
@wraps(func)
def timed_func(*args, **kwargs):
start = time()
ret = func(*args, **kwargs)
end = time()
print(f'[{func.__qualname__}] Time taken: {end - start}')
return ret
return timed_func
class RMath:
def __init__(self, a, b):
self.a = a
self.b = b
@Handlers.timeit
def add(self):
try:
# add a `return` here!
return self.a + self.b
except Exception as e:
return e
a = 10
b = 20
m = RMath(a, b)
c = m.add()
print(c)
出去:
[RMath.add] Time taken: 3.0994415283203125e-06
30
更新: *args, **kwargs*
是一種通用方法來處理帶有任意數量參數的 function,但是如果您明確地只想支持RMath.add()
方法 - function 采用單個參數self
- 您可以使用稍微不同的方法,如下所示:
@wraps(func)
def timed_func(self):
start = time()
ret = func(self)
end = time()
print(f'[{func.__qualname__}] Time taken: {end - start}')
return ret
有許多較小的事情需要修復才能完成這項工作。 您必須從裝飾器返回內部 function,而不是調用 function 的結果。 You also have to marshal the arguments given to the original function through your function - and you need to return the result from your wrapped function after computing the time spent.
而且由於您從未創建Handler
實例,因此您應該將包裝 function 定義為 static 方法(即使您不這樣做,它仍然可以工作,但不會有self
)。
import time
class Handlers():
# make sure we don't require an instance
@staticmethod
def timeit(func):
def timefunc(*args, **kwargs):
# ^--- needs to accept and marshal the arguments
start = time.time()
result = func(*args, **kwargs)
# ^- keep result ^--- marshal the arguments
end = time.time()
print('Time taken: ', end - start)
return result
# ^- return the result of calling the wrapped function
return timefunc
# ^-- return the function, not the result of calling the function
class RMath():
def __init__(self, a, b):
self.a = a
self.b = b
@Handlers.timeit
def add(self):
try:
return self.a + self.b
# ^--- needs to return the result of the addition
except Exception as e:
return e
a = 10
b = 20
m = RMath(a, b)
c = m.add()
print(c)
正如現在所寫,您需要一個Handlers
實例來運行Handlers.timeit()
,因此您需要實例化 class 並使用該實例的timeit()
方法來裝飾其他類中的方法。
但我認為您想要做的是使用 class 作為命名空間來保存方法。 在這種情況下,您可以使用@staticmethod
裝飾方法。 畢竟,該方法實際上並未使用 class 的實例。
class Handlers():
@staticmethod
def timeit(func):
def timefunc():
start = time.time()
func()
end = time.time()
print('Time taken: ', end - start)
return timefunc()
或者您可以將它用作任何 class 之外的普通 function,或者(可能是最好的主意)將它放在您導入的單獨模塊中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.