我在Python中玩上下文管理器和装饰器,并制作了一个可调用的上下文管理器装饰器类。我让它装饰一个函数,我想在这个函数中修改decorator类中的一个属性。下面是装饰器类的一个简单版本:
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
。但是,我想将CallableDecorator
中的foo
属性从bar
更改为bar
函数中计算的值,但在定义bar
时未知。是否有访问权限?
我不是在问这是否是一个好的设计,也不是在问什么时候会有用,我只是想知道如何做到这一点。
当包装器调用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
以便CCD_ 11可以接受decorator对象作为参数,并在函数内部设置其CCD_
@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