как реализовать декораторы для рекурсивной функции в классе - PullRequest
0 голосов
/ 24 апреля 2019

Я пишу класс, который принимает входной список целых чисел при инициализации.У класса есть куча методов сортировки.Я хотел добавить декоратор, который будет перетасовывать список ввода перед каждым вызовом метода.При попытке реализовать рекурсивную сортировку по пузырькам декоратор вызывает RecursionError: maximum recursion depth exceeded in comparison

Я попытался передать аргумент self, чтобы декоратор мог получить доступ к переменной класса.Однако мне нужна помощь, чтобы позволить рекурсивной функции работать с декоратором

import functools
from searching import timer
import random


def shuffle(func):
    @functools.wraps(func)
    def wrapper(self, *args, **kwargs):
        random.shuffle(self.ip_list)
        value = func(self, *args, **kwargs)
        return value
    return wrapper


class sorting:
    def __init__(self, ip_list):
        self.ip_list = ip_list
        self.n = len(self.ip_list)
        self.timer_dict = {}

    @shuffle
    @timer
    def recursive_bubble_sort(self):
        print(self.ip_list)
        for j in range(self.n):
            try:
                if self.ip_list[j] > self.ip_list[j+1]:
                    self.ip_list[j], self.ip_list[j + 1] = self.ip_list[j + 1], self.ip_list[j]
                    self.recursive_bubble_sort()
            except IndexError:
                pass
        print(self.ip_list)


x = [i for i in range(0,30)]
s = sorting(x)
s.recursive_bubble_sort()

1 Ответ

3 голосов
/ 24 апреля 2019

Это очень плохая идея - декорировать рекурсивный метод, подобный тому, что был в вашем примере.Для некоторых методов и декораторов это может работать, но не алгоритм сортировки.Проблема в том, что каждый рекурсивный вызов будет заканчиваться вызовом через оболочку декоратора.С вашим shuffle декоратором это означает, что вы будете переставлять список при каждом рекурсивном вызове, поэтому ваш список никогда не сортируется.Даже если сортировка не перетасовывается при каждом вызове, у вашего timer декоратора, вероятно, будет аналогичная проблема, так как он будет пытаться рассчитать время каждого рекурсивного вызова, а не только вызов верхнего уровня функции.

Одним из вариантов может быть разделение рекурсивного метода и декорированного метода.Часто это хороший способ спроектировать API для функции, которая в любом случае будет реализована с рекурсией, поскольку вам часто нужно будет передавать дополнительные аргументы в рекурсивные вызовы, но вызов верхнего уровня не нуждается в них.

@shuffle
@timer
def bubble_sort_recursive(self):        # despite the name, this function is not recursive itself
    self.bubble_sort_recursive_helper()

def bubble_sort_recursive_helper(self): # all the recursion happens in this helper method
    ... # recursive code goes here, recursive calls should be to the helper!
...