Как вызвать вызов функции только один раз в конкретном классе, который наследует абстрактный базовый класс? - PullRequest
0 голосов
/ 04 февраля 2020

Я реализовал шаблон состояния из «Банды четырех» в Python, и я хотел бы, чтобы метод entry() вызывался один раз при первом вызове моего handle метода. Я знаю, что могу сделать это легко, используя логическое свойство и условие if, но я бы хотел сделать его «невидимым» для пользователя. Так что я возился с декораторами, но я не могу заставить вещи работать с методами классов с наследованием ... Не могли бы вы сказать, что я делаю неправильно, или есть лучшее решение этой проблемы?

Вот мой пример кода: Абстрактный класс State:

class TriggerOnce(object):
    def __init__(self, fcall):
        self.fcall = fcall
        self.triggered = False

    def __call__(self, obj, *args, **kwargs):
        if not self.triggered:
            self.fcall(obj, *args, **kwargs)
            self.triggered = True
            obj.__call__(*args, **kwargs)


# I know this will trigger more than once, but just to try
def trigger_once(fn, fcall=None):
    def trigger(*args, **kwargs):
        if fcall:
            fcall()
        return fn(*args, **kwargs)
    return trigger

class State(metaclass=ABCMeta):
    @property
    def context(self):
        return self._context

    @context.setter
    def context(self, context) -> None:
        self._context = context

    @abstractmethod
    def entry(self) -> None:
        pass

    @abstractmethod
    def handle(self, class_id: int) -> None:
        pass

Конкретный класс State:

class PersonState(State):
    valid_transitions = [
        "DriveForkliftState",
        "UnknownState"
    ]
    class_id = [3]

    def entry(self) -> None:
        self.context.objects_tree.set_update(OBJECT_CLASSES.index("person"), True)

    @TriggerOnce(entry)
    def handle(self, class_id: int) -> None:
        if class_id in self.class_id:
            return
        new_state = None
        for state in self.valid_transitions:
            state_class = getattr(importlib.import_module(self.__module__), state)
            if class_id in state_class.class_id:
                new_state = state_class()
                break
        if new_state is not None:
            self.context.transition_to(new_state)
...