Функция декоратора для предотвращения рекурсии в методах класса - PullRequest
0 голосов
/ 06 мая 2020

Я столкнулся с проблемами рекурсии и пытался как-то решить эту проблему pythoni c.

Лучший подход для предотвращения повторного рекурсивного вызова функции Я предпочитаю использовать декоратор, содержащий блокировку вызова внутри try /finally.

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

class Once:
    """Decorator object approach"""
    def __init__(self, func):
        self._func = func
        self._iscalling = False

    def __call__(self, *args, **kwargs):
        if self._iscalling:
            print("Preventing recursive call of ", self._func)
            return

        try:
            self._iscalling = True
            print("Starting...")
            return self._func(*args, **kwargs)
        except Exception as e:
            print(e)
        finally:
            print("Done.")
            self._iscalling = False

class Emitter:
    """Handles functions in list and calls them all"""
    def __init__(self, m: "Master"):
        self.funcs = list()
        self.m = m
        self.running = False

    def add_fnc(self, fnc):
        self.funcs.append(fnc)

    def once(self, old_fnc):
        """Function decorator approach"""
        def new_func(*args, **kwargs):
            if self.running:
                print("Prevented execution!")
                return
            try:
                self.running = True
                print("Starting...")
                old_fnc(*args, **kwargs)
            except Exception as e:
                print(e)
            finally:
                print("Done.")
                self.running = False
        return new_func

    @Once  # (class) run() missing 1 required positional argument: 'self'
    # @once  # (function) TypeError: once() missing 1 required positional argument: 'old_fnc'
    def run(self):
        """This function must not run recursively"""
        print("Emitting calls...")
        for f in self.funcs:
            f(self.m)  # Calling with ref to master
        print("Emitting calls done")


class Master:
    def __init__(self):
        self.emitter = Emitter(self)

    def run(self):
        self.emitter.run()


def greet(m: Master):
    """Simple ugly function causing recursion"""
    print("Master greets us! Greet back.")
    m.run()  # Starting recursion


master = Master()
master.emitter.add_fnc(greet)
master.run()

Я также пробовал некоторые из functools, как в примерах, но ничего не менял.

Спасибо

...