我正在使用Python来管理上下文管理器和装饰器,并制作了一个可调用的上下文管理器装饰器类。我在需要修饰装饰器类中的属性的装饰函数。这是装饰器类的简单版本:
class CallableDecorator:
def __init__(self):
print('Creating decorator')
self.foo = None
def __enter__(self):
print('Entering Decorator')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print(f'Exiting Decorator with attribute foo = {self.foo}')
def __call__(self, func):
print('Starting the call in Decorator')
@wraps(func)
def wrapper(*args, **kwargs):
with self:
print('In wrapped context manager')
return func(*args, **kwargs)
print('About to finish call in Decorator')
return wrapper
然后我要包装一个函数
@CallableDecorator()
def bar():
something = do_stuff()
setattr(callable_decorator, 'foo', something)
print('bar')
这将立即打印
Creating decorator
Starting the call in Decorator
About to finish call in Decorator
因为这几乎调用了CallableDecorator()bar()
,所以在创建此函数时将创建CallableDecorator
类型的对象。调用bar()
之后,将显示以下内容:
Entering Decorator
In wrapped context manager
bar
Exiting Decorator with foo = None
这也是可以预期的,因为现在我打电话给wrapper
。但是,我想将foo
中CallableDecorator
中的bar
属性更改为在bar
函数中计算出的值,但在定义时尚不知道bar
。反正有访问权限吗?
我不是问这是一个好的设计,还是什么时候有用,我只是想了解如何做到这一点。
答案 0 :(得分:0)
您可以使包装器在调用func
时将装饰器对象本身作为参数传递:
class CallableDecorator:
def __call__(self, func):
print('Starting the call in Decorator')
@wraps(func)
def wrapper(*args, **kwargs):
with self:
print('In wrapped context manager')
return func(self, *args, **kwargs)
print('About to finish call in Decorator')
return wrapper
以便func
可以接受装饰器对象作为参数并在函数中设置其foo
属性:
@CallableDecorator()
def bar(decorator):
decorator.foo = 'bar'
进行这些更改后,您的代码将输出:
Creating decorator
Starting the call in Decorator
About to finish call in Decorator
Entering Decorator
In wrapped context manager
Exiting Decorator with attribute foo = bar