`__init__` 装饰器如果为空则处理参数
`__init__` decorator that handles args if empty
假设我有一个 class 这样的:
class Test:
def __init__(self, a, b):
self.a = a
self.b = b
我的目标是创建一个 decorator
来处理填充 init
参数(如果它们不存在),即:
class Test:
@autoinit
def __init__(self, a, b):
self.a = a
self.b = b
其中 @autoinit
定义如下:
class autoinit:
def __init__(self, data = {"a": "test_a", "b": "test_b"}):
self.data = data
def __call__(self, func):
decorator = self
def wrapper(*args, **kwargs):
print(decorator.data)
func(self, **decorator.data)
print(decorator.data)
return wrapper
因此,它会自动将Test
属性分别分配给test_a, test_b
。
理想的用法是这样的:
test = Test(a="test_z", b="test_x")
test.a == "test_z"
test.b == "test_x"
# however,
test = Test()
test.a == "test_a"
test.b == "test_b"
# but also,
test = Test(a="test_z")
test.a == "test_z"
test.b == "test_b"
我将始终在 Test
class 中找到与 data
字典中的键相匹配的参数。
这可能吗?什么是最干净的实现?
更新:
预期用途跨越许多独立的 classes。例如,假设我有一个这样的全局配置:
config = {
"resourceA": {"a": "test_a", "b": "test_b"},
"resourceB": {"name": "foo", "value": "bar"}
}
装饰器 @autoinit(resource="resourceA")
的目标是使用 **config[resource]
填充给定 class.
的所有 __init__
值
我会这样写:
def autoinit(**kwargs):
if not kwargs:
kwargs = {"a": "test_a", "b": "test_b"} # some default
def wrapper(f):
def wrapped(*args, **overrides):
kwargs.update(overrides) # update kwargs with overrides
return f(*args, **kwargs)
return wrapped
return wrapper
这允许实施 class 如您的问题所述:
class Test:
@autoinit()
def __init__(self, a, b):
self.a = a
self.b = b
t = Test()
assert t.a = 'test_a'
assert t.b = 'test_b'
t2 = Test(a='test_z')
assert t2.a = 'test_z'
assert t2.b = 'test_b'
综上所述,请考虑使用教你 class 如何从配置本身读取的 mixin。
from abc import ABC
class ConfigurationDefault(ABC):
@classmethod
def with_config_defaults(cls, config, **kwargs):
new_kwargs = {**config, **kwargs}
return cls(**new_kwargs)
class Test(ConfigurationDefault):
def __init__(self, a, b):
self.a = a
self.b = b
config = {'resources': {'a': 'test_a', 'b': 'test_b'}}
t = Test.with_config_defaults(config['resources'])
t2 = Test.with_config_defaults(config['resources'], a='test_z')
假设我有一个 class 这样的:
class Test:
def __init__(self, a, b):
self.a = a
self.b = b
我的目标是创建一个 decorator
来处理填充 init
参数(如果它们不存在),即:
class Test:
@autoinit
def __init__(self, a, b):
self.a = a
self.b = b
其中 @autoinit
定义如下:
class autoinit:
def __init__(self, data = {"a": "test_a", "b": "test_b"}):
self.data = data
def __call__(self, func):
decorator = self
def wrapper(*args, **kwargs):
print(decorator.data)
func(self, **decorator.data)
print(decorator.data)
return wrapper
因此,它会自动将Test
属性分别分配给test_a, test_b
。
理想的用法是这样的:
test = Test(a="test_z", b="test_x")
test.a == "test_z"
test.b == "test_x"
# however,
test = Test()
test.a == "test_a"
test.b == "test_b"
# but also,
test = Test(a="test_z")
test.a == "test_z"
test.b == "test_b"
我将始终在 Test
class 中找到与 data
字典中的键相匹配的参数。
这可能吗?什么是最干净的实现?
更新:
预期用途跨越许多独立的 classes。例如,假设我有一个这样的全局配置:
config = {
"resourceA": {"a": "test_a", "b": "test_b"},
"resourceB": {"name": "foo", "value": "bar"}
}
装饰器 @autoinit(resource="resourceA")
的目标是使用 **config[resource]
填充给定 class.
__init__
值
我会这样写:
def autoinit(**kwargs):
if not kwargs:
kwargs = {"a": "test_a", "b": "test_b"} # some default
def wrapper(f):
def wrapped(*args, **overrides):
kwargs.update(overrides) # update kwargs with overrides
return f(*args, **kwargs)
return wrapped
return wrapper
这允许实施 class 如您的问题所述:
class Test:
@autoinit()
def __init__(self, a, b):
self.a = a
self.b = b
t = Test()
assert t.a = 'test_a'
assert t.b = 'test_b'
t2 = Test(a='test_z')
assert t2.a = 'test_z'
assert t2.b = 'test_b'
综上所述,请考虑使用教你 class 如何从配置本身读取的 mixin。
from abc import ABC
class ConfigurationDefault(ABC):
@classmethod
def with_config_defaults(cls, config, **kwargs):
new_kwargs = {**config, **kwargs}
return cls(**new_kwargs)
class Test(ConfigurationDefault):
def __init__(self, a, b):
self.a = a
self.b = b
config = {'resources': {'a': 'test_a', 'b': 'test_b'}}
t = Test.with_config_defaults(config['resources'])
t2 = Test.with_config_defaults(config['resources'], a='test_z')