Задание 1. Онлайн-платёжные системы
Условие: создайте абстрактный класс PaymentProcessor с методом pay(amount). Реализуйте два класса:
PaypalPayment— печатаетPaid {amount} via PayPal.CreditCardPayment— печатаетPaid {amount} via Credit Card.
Что должно получиться: можно создать список платёжных процессоров и вызвать pay() для каждого.
Подсказка: не забудьте наследовать PaymentProcessor от ABC.
Задание 2. Проверка платежей
Условие: доработайте систему из задания 1:
- Создайте пользовательское исключение
InvalidPaymentError. - В каждом платёжном классе метод
pay(amount)должен проверять сумму: - Если сумма меньше или равна нулю, выбрасывать
InvalidPaymentError. - Иначе проводить платёж.
Что должно получиться: отрицательная сумма вызывает InvalidPaymentError, который можно перехватить.
Подсказка: вынесите общую проверку суммы в метод или статический метод базового класса, чтобы не дублировать код.
Задание 3. Фигуры и площади
Условие: создайте абстрактный класс Shape с методом area(). Реализуйте:
Circle(radius)— площадь круга.Rectangle(width, height)— площадь прямоугольника.
Что должно получиться:
shapes = [Circle(3), Rectangle(4, 5)]
for shape in shapes:
print(f"Area: {shape.area():.2f}")
Подсказка: для числа π используйте math.pi.
Задание 4. Проверка размеров фигур
Условие: доработайте фигуры из задания 3:
- Добавьте проверку в конструкторы
CircleиRectangle, чтобы значения были положительными. - Если передано отрицательное или нулевое значение, выбрасывайте пользовательское исключение
InvalidSizeError.
Что должно получиться: при попытке создать Circle(-1) или Rectangle(0, 5) возникает InvalidSizeError.
Подсказка: чтобы InvalidSizeError можно было ловить и как ValueError, наследуйте его от ValueError.
Задание 5 ★. Итератор диапазона
Условие: создайте класс Countdown, который принимает число start и итерируется от start до 1 включительно.
for n in Countdown(5):
print(n) # 5 4 3 2 1
Что должно получиться: объект поддерживает протокол итератора.
Подсказка: реализуйте __iter__ и __next__. Не забудьте выбросить StopIteration.
Задание 6 ★★. Умная дверь с блокировкой
Условие: реализуйте класс Door — кодовый замок, который блокируется после нескольких неудачных попыток.
Исключение: DoorBlockedError — выбрасывается при обращении к заблокированной двери.
Атрибуты:
code— текущий код доступа;failed_attempts— счётчик неудачных попыток;max_attempts— максимум попыток (по умолчанию 3);block_duration— длительность блокировки;block_until— момент окончания блокировки.
Методы:
__init__(code, max_attempts=3, block_minutes=15.0)— инициализация двери;unlock(code)— попытка открыть дверь;change_code(old_code, new_code)— смена кода;is_valid_code(code)— проверка правильности кода;is_blocked()— проверка, заблокирована ли дверь;remaining_block_time()— оставшееся время блокировки;check_block()— проверка блокировки перед операцией;handle_failed_attempt()— обработка неудачной попытки;reset_attempts()— сброс счётчика попыток.
Логика работы:
- Любой вызов
unlock()илиchange_code()сначала проверяет блокировку. Если дверь заблокирована — сразуDoorBlockedError. - Правильный код → успех и сброс счётчика неудач.
- Неправильный код → отказ и увеличение счётчика.
- Счётчик достиг
max_attempts→ дверь блокируется наblock_minutesминут. change_code()требует правильный старый код; при ошибке код не меняется.
Что должно получиться:
door = Door("1234", max_attempts=3, block_minutes=15)
door.unlock("0000") # Access denied (попытка 1 из 3)
door.unlock("1111") # Access denied (попытка 2 из 3)
door.unlock("2222") # Too many failed attempts — дверь заблокирована
door.unlock("1234") # DoorBlockedError, даже с правильным кодом
Подсказка: для времени используйте datetime.now() и timedelta(minutes=...). Блокировка активна, пока block_until ещё не наступил.