假设您有一个配置类(如Django' settings.py
样式设置),它在应用程序启动时设置。你加载它就好了。
from myapp import config
CONF = config.CONF
您希望将此配置中的某个变量用作装饰器参数,如此。
@decorators.mydecorator(run_timeout=CONF.timeout)
def run_stuff_once():
# blah, blah, blah...
@decorators.mydecorator(interval=CONF.interval)
def run_stuff_periodically():
# blah, blah, blah...
如果运行此命令,配置变量将在运行时加载,永远不会更改。即使不使用装饰器,我们也可以看到这种情况发生。
>>> class Config(object):
... x = 5
...
>>> config = Config()
>>>
>>> def func(param=config.x):
... print(param)
...
>>> func()
5
>>> config.x = 9
>>> func()
5
这会导致两个问题:
这可以解决吗?如果我在谈论"正常函数",我会采用类似于解决PyLint W0102警告的解决方案,即
>>> def func2(param=None):
... if param is None:
... param = config.x
... print(param)
...
>>> func2()
9
>>> config.x = 5
>>> func2()
5
但是,不可能为装饰器执行此操作,因为如上所示,传递给装饰器的值可能会更改。我对此案的解决方案感到难过。
答案 0 :(得分:1)
这应该提供一个动态装饰器,它在运行时而不是在定义时
进行评估class Config(object):
x = 5
y = 6
config = Config()
config2 = Config()
# takes object and atribute as arguments
def dynamic_dec(reference,atrib,kw=None):
# gets function pointer to wraped function
def dynamic_dec_functor(functor):
# creates lamda function to revalueate config value
def func_wrapper(ref_wrapper=(lambda ref=reference: getattr(ref,atrib))):
#call original function with result of lambda
if(kw):
#store lambda result to keyword arg
functor(**{kw:ref_wrapper()})
else:
#pass lambda result to positional arg
functor(ref_wrapper())
return func_wrapper
return dynamic_dec_functor
@dynamic_dec(config,'x','param')
def func(param="default"):
print(param)
@dynamic_dec(config2,'y')
def func2(param):
print(param)
#time to test
print("\n call func and func2 with original config \n")
func()
func2()
print("\n update original config \n")
config.x = 9
config.y = 10
print("\n call func and func2 after config change \n")
func()
func2()
print("\n func2 did not change as it used a different config object \n")