【发布时间】:2020-08-04 01:39:12
【问题描述】:
我有一个装饰器,可以帮助定义来自全局配置文件的类属性。该函数如下所示:
config_data = {
"resourceA": {"a": "foo", "b": "bar"},
"resourceB": {"x": "baz", "y": "boo"}
}
def autoinit(resource: str = None, data: dict = config_data, **kwargs):
print(f'here for {resource}')
if not kwargs:
if resource:
kwargs = data[resource] # get defaults
def wrapper(func):
def wrapped(*args, **configs):
kwargs.update(configs) # update kwargs with overrides
return func(*args, **kwargs)
return wrapped
return wrapper
这个装饰器的行为方式是,如果我有一个类:
class ResourceA:
@autoinit(resource="resourceA")
def __init__(self, a, b):
self.a = a
self.b = b
# other stuff
class ResourceB:
@autoinit(resource="resourceB")
def __init__(self, x, y):
self.x = x
self.y = y
# other stuff
将自动从数据配置中设置。
现在,当我执行导入时
from module.submodule import ResourceA
我的结果是:
here for resourceA
here for resourceB
当我还没有实例化类时,为什么会调用装饰器?
这是我遇到的真正问题的虚拟版本。它打断了我的测试,因为data: dict = config_data 实际上是从默认文件加载的。当我运行测试时,存在一个默认文件不存在的版本,但我无法通过它。
有什么想法吗?
【问题讨论】:
-
嗯,因为这就是装饰器的工作方式。 装饰器在你调用它时被调用!即
@autoinit,相当于def __init__(self,) ...; __init__ = autoinit(__init__)。你的装饰器返回一个包装器,当你实例化类时 that 会被调用。 -
导入时创建类并执行其中的方法定义(不是方法本身的代码)以将函数注册为方法。这也包括装饰器(如果存在)。
-
@juanpa.arrivillaga,想把它作为答案发布吗?
-
@sgerbhctim 是的,当您导入模块时,全局范围内的类定义会执行(全局范围内的所有内容都会执行),然后您在类定义中调用装饰器。
-
@sgerbhctim 将
def autoinit下面的四行移动到def wrapper下面