Декоратор класса для проверки переменных класса [closed]

У меня около 20 различных классов, каждый из которых содержит несколько переменных класса. Переменные инициализируются как None и загружается из разных конфигов в зависимости от выбранного режима. Образец кода:

class Class1:
    VAR1 = VAR2 = VAR3 = VAR4 = None

    def __init__(self):
        pass

    def method1(self):
        pass

    @staticmethod
    def method2():
        pass

Мне нужно вызвать исключение, если какой-либо из методов класса вызывается до загрузки всех переменных класса.

С самого начала я решил, что добавление условий к каждому методу – плохое решение, поэтому сделал следующие декораторы:

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

Теперь я могу украсить все методы класса:

@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

Это работает и решает мою проблему, но я чувствую, что есть более элегантное решение.

Не могли бы вы мне посоветовать еще что-нибудь, что не требует серьезных изменений архитектуры? Может быть, есть какой-то способ метакласса, который я пропустил …

0

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *