I have around 20 different classes each contains several class variables. Variables initialized as
None and loaded from various configs depending on chosen mode. Sample code:
class Class1: VAR1 = VAR2 = VAR3 = VAR4 = None def __init__(self): pass def method1(self): pass @staticmethod def method2(): pass
I need to throw an exception if any of class methods called before all class variables loaded.
From start I decided that adding conditions to every method is bad solution, so I made this decorators:
from functools import wraps def for_all_methods(decorator): """ Patched from https://stackoverflow.com/a/6307868/10824407 """ def decorate(cls): for attr in cls.__dict__: if callable(getattr(cls, attr)): setattr(cls, attr, decorator(cls, getattr(cls, attr))) return cls return decorate def check(variables=None, check_func=lambda x: x is not None): def decorator(cls, func): @wraps(func) def wrapper(*args, **kwargs): if variables is not None: for variable_name in variables: variable = getattr(cls, variable_name) if variable is None or not check_func(variable): raise Exception("Check failed") return func(*args, **kwargs) return wrapper return decorator
Now I can decorate all class methods:
@for_all_methods(check(("VAR1", "VAR2", "VAR3", "VAR4"))) class Class1: VAR1 = VAR2 = VAR3 = VAR4 = None def __init__(self): pass def method1(self): pass @staticmethod def method2(): pass Class1.method2() # throws an error Class1.VAR1, Class1.VAR2, Class1.VAR3, Class1.VAR4 = range(4) Class1.method2() # doesn't throw an error
It works and solve my problem, but I feel like there’s more elegant solution.
Could you advice me something else which doesn’t require major architecture changes? Maybe there’s some metaclass way which I skipped…