В некоторых случаях полезно накапливать результат, а затем получать его единым списком.
Реализуйте декоратор 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”). Вызов с любым другим методом будет проигнорирован.
Посмотреть код
Решение
# упрщенный вариант
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
Решение
# концептуально более правильный вариант
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
Здравствуйте.
Скажите, пожалуйста, а зачем используется **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
**kwargs позволяет передать все именованные переменные не имеющие отношения к нашему декоратору наряду с неименованными в целевую функцию.
func(*args, **kwargs)
copy() как вариант тоже правильный. Просто про copy() рассказывали в материалах, а про два оставшихся способа скопировать список – по-моему, нет.
В вашем варианте есть только один недостаток – method у нас не может быть None, потому что для него установлено значение по-умолчанию.
В окне комментария есть виджет вставки кода. Он не крутой, на крутой денег нет, но позволяет сохранять форматирование кода без дополнительных телодвижений.
Ограничение на длину поправил, теперь можно все целиком вставлять.
Большое спасибо за подробный ответ!