Решение 1. Фабрика функций расчёта НДС
def vat_calculator(rate: float):
def calculate(price: float) -> float:
return round(price * (1 + rate), 2)
return calculate
vat_20 = vat_calculator(0.2)
vat_10 = vat_calculator(0.1)
print(vat_20(100)) # 120.0
print(vat_10(200)) # 220.0
Логика: внешняя функция запоминает rate в замыкании. Каждый вызов vat_calculator создаёт независимую функцию со своей ставкой.
Решение 2. Калькулятор скидок по категориям
def discount_maker(category_discounts: dict[str, float]):
def apply_discount(category: str, price: float) -> float:
discount = category_discounts.get(category, 0)
return round(price * (1 - discount), 2)
return apply_discount
discounts = {"food": 0.1, "clothes": 0.2}
friday_discount = discount_maker(discounts)
print(friday_discount("food", 100)) # 90.0
print(friday_discount("clothes", 250)) # 200.0
print(friday_discount("electronics", 500)) # 500
Логика: category_discounts захватывается из Enclosing-области. Метод dict.get возвращает 0, если категория не найдена, поэтому цена не меняется.
Решение 3. Настроенная функция вывода
def custom_printer(sep: str, end: str):
def print_func(*args) -> None:
print(*args, sep=sep, end=end)
return print_func
printer = custom_printer(sep=' | ', end=' -->\n')
printer('Hello', 'World')
printer('Python', 'Java', 'C++')
Логика: *args собирает все позиционные аргументы, а sep и end берутся из замыкания. Значения по умолчанию нельзя переопределить при вызове printer, что и требуется по условию.
Решение 4. Нумерация вызовов функции
def call_counter(func):
count = 0
def wrapper() -> None:
nonlocal count
count += 1
print(f"Вызов функции '{func.__name__}' №{count}:")
func()
return wrapper
@call_counter
def greet():
print("Привет!")
greet()
greet()
greet()
Логика: декоратор возвращает вложенную функцию wrapper. Счётчик count хранится в замыкании и увеличивается через nonlocal при каждом вызове.
Проверить по документации: декораторы с сохранением метаданных функции часто используют
functools.wraps. Подробнее — в документации functools.