E. Накопление результата

В некоторых случаях полезно накапливать результат, а затем получать его единым списком.

Реализуйте декоратор result_accumulator, который модернизирует функцию с неопределенным количеством позиционных параметров следующим образом:

  • Добавляет именованный параметр method со значением по умолчанию accumulate;
  • При вызове функции с параметром method равным accumulate, результат сохраняется в очередь (для каждой функции в собственную), а функция ничего не возвращает;
  • При вызове функции с параметром method равным drop, возвращается все накопленные результаты, а очередь сбрасывается.

Примечание

Ваше решение должно содержать только функции.
В решении не должно быть вызовов требуемых функций.

Пример

Ввод

@result_accumulator
def a_plus_b(a, b):
    return a + b


print(a_plus_b(3, 5, method="accumulate"))
print(a_plus_b(7, 9))
print(a_plus_b(-3, 5, method="drop"))
print(a_plus_b(1, -7))
print(a_plus_b(10, 35, method="drop"))

Вывод

None
None
[8, 16, 2]
None
[-6, 45]

Ввод

@result_accumulator
def get_letters(text: str) -> str:
    return ''.join(sorted(set(filter(str.isalpha, text.lower()))))


print(get_letters('Hello, world!'))
print(get_letters('Декораторы это круто =)'))
print(get_letters('Ехали медведи на велосипеде', method='drop'))

Вывод

None
None
['dehlorw', 'адекортуыэ', 'авдеилмнопсх']

Решение

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

Если раньше наша функция сразу возвращала результат, то теперь она его не возвращает, а “накапливает” и возвращает сразу списком только в том случае, если в качестве параметра был указано конкретное значение-сигнал.

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

Я публикую два решения – первое частное, оно хорошо подходит для решения именно э того задания, но имеет концептуальный недостаток – оно предполагает что мы в любом случае хотим “накопить” результат. Второй вариант будет накапливать результат только если это прямо указано (отсутствие метода, метод накопления или использования метода “drop”). Вызов с любым другим методом будет проигнорирован.

Посмотреть код

Решение

Python
# упрщенный вариант

def result_accumulator(func):
    queue = []

    def wrapper(*args, method='accumulate', **kwargs):
        queue.append(func(*args, **kwargs))
        if method == 'drop':
            result = list(queue)
            queue.clear()
            return result
    return wrapper

Решение

Python
# концептуально более правильный вариант

def result_accumulator(func):
    queue = []

    def wrapper(*args, method='accumulate', **kwargs):
        if method == 'accumulate':
            queue.append(func(*args, **kwargs))
        elif method == 'drop':
            queue.append(func(*args, **kwargs))
            result = queue[:]
            queue.clear()
            return result
    return wrapper
Подписаться
Уведомить о
guest
3 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
Ольга
Ольга
07.10.2024 14:57

Здравствуйте.
Скажите, пожалуйста, а зачем используется **kwargs при наличии именованного аргумента method?
Актуально ли отдельно учесть отсутствие метода (по аналогии с отдельным учетом ‘accumulate’ во 2-м варианте)?
И эффективно ли использовать .copy() при методе ‘drop’?
def result_accumulator(old_func):
    lst = [] 
    def new_func(*args, method=‘accumulate’):
         if method == ‘accumulate’:
             lst.append(old_func(*args))
         if method is None:
             lst.append(old_func(*args))
         if method == ‘drop’:
             lst.append(old_func(*args))
             temp = lst.copy()
             lst.clear()
         return temp
     return new_func

Ольга
Ольга
Ответить на  Сергей Клочко
07.10.2024 16:02

Большое спасибо за подробный ответ!