我正在遵循David Beazley's Python Cookbook的Class Decorator食谱,该食谱似乎更合适,因为它使用functools.wraps
为装饰者提供了更好的组织和属性。
但是,我不清楚如何(或是否)从装饰器本身内部访问实例的属性。这是代码段:
import time
import types
from functools import wraps
class TimeDecorator():
def __init__(self, func):
wraps(func)(self)
def __call__(self, *args, **kwargs):
tic = time.time()
func_return = self.__wrapped__(*args, **kwargs)
tac = time.time()
total_time = round((tac - tic) / 60, 2)
print(f'Operation Time: {total_time} min.')
# print(self.__wrapped__.test_attr) # going to give an error...
return func_return
def __get__(self, instance, cls):
if instance is None:
return self
else:
return types.MethodType(self, instance)
class A():
def __init__(self):
self.test_attr = 0
@TimeDecorator
def do_something(self):
time.sleep(1) # example of stuff only...
我尝试通过装饰器的__call__
到self.__wrapped__.test_attr
或self.__wrapped__.__self__.test_attr
访问实例,但是所有人都告诉我:
AttributeError: 'function' object has no attribute 'test_attr'
那么在这种情况下,我将如何访问修饰的类的属性?还是我必须使用另一种方式来构建我的装饰器?
答案 0 :(得分:2)
您正在将装饰器应用于实例方法,因此将将此装饰方法绑定到的实例作为第一个参数self
传入,您可以在其中找到实例属性。重新寻找,因此您只需从以下示例中名为self
的参数中提取wrapped_self
:
def __call__(self, wrapped_self, *args, **kwargs):
tic = time.time()
func_return = self.__wrapped__(wrapped_self, *args, **kwargs)
tac = time.time()
total_time = round((tac - tic) / 60, 2)
print(f'Operation Time: {total_time} min.')
print(wrapped_self.test_attr)
return func_return
答案 1 :(得分:1)
“ self”是do_something函数的第一个参数。
因此您可以在装饰器中明确标识它。
wrapped
将成为修饰的类实例,而*args
将包含所有其他位置参数。
from functools import wraps
import types
import time
class TimeDecorator():
def __init__(self, func):
wraps(func)(self)
def __call__(self, wrapped, *args, **kwargs):
tic = time.time()
func_return = self.__wrapped__(wrapped, *args, **kwargs)
tac = time.time()
total_time = round((tac - tic) / 60, 2)
print(f'Operation Time: {total_time} min.')
print(wrapped.test_attr)
return func_return
def __get__(self, instance, cls):
if instance is None:
return self
else:
return types.MethodType(self, instance)
class A():
def __init__(self):
self.test_attr = 0
@TimeDecorator
def do_something(self):
time.sleep(1) # example of stuff only...
a = A()
a.do_something()