""" Урок 76. Абстрактные классы и пользовательские исключения — весь код примеров одним файлом. Источник: subjects/python-fundamentals/course/lessons/76-abstract-classes-exceptions/examples.html Файл собран автоматически (tools/build_lesson_examples.py): правьте страницу урока. Запуск: python lesson-76.py """ # ==================================================================== # Пример 1. Абстрактный класс сотрудников # ==================================================================== from abc import ABC, abstractmethod class Employee(ABC): """Abstract base class for company employees.""" def __init__(self, name: str) -> None: self.name = name @abstractmethod def work(self) -> None: """Describe what the employee does. Must be implemented.""" pass def take_break(self) -> None: """Common behavior for all employees.""" print(f"{self.name} is taking a break.") class Programmer(Employee): def work(self) -> None: print(f"{self.name} writes code.") class Designer(Employee): def work(self) -> None: print(f"{self.name} creates layouts.") # employee = Employee("Bob") # TypeError! programmer = Programmer("Alice") programmer.work() programmer.take_break() # ==================================================================== # Пример 2. Пользовательское исключение с данными # ==================================================================== class AccessDeniedError(Exception): """Raised when the user does not meet age requirements.""" def __init__(self, age: int, min_age: int = 18) -> None: self.age = age self.min_age = min_age super().__init__(f"Access denied: age {age} is below minimum {min_age}") def check_age(age: int) -> None: if age < 18: raise AccessDeniedError(age) print("Access granted") try: check_age(16) except AccessDeniedError as e: print("Error:", e) print("Age:", e.age) print("Minimum age:", e.min_age) # ==================================================================== # Пример 3. Исключение на основе ValueError # ==================================================================== class TemperatureTooLowError(ValueError): """Raised when temperature is below absolute zero.""" pass def set_temperature(value: float) -> None: if value < -273.15: raise TemperatureTooLowError("Temperature cannot be below absolute zero") print(f"Temperature set to {value}°C") for temp in (15, -300): try: set_temperature(temp) except TemperatureTooLowError as e: print("Caught:", e) except ValueError as e: # Этот блок тоже сработал бы, потому что TemperatureTooLowError — наследник ValueError print("Caught as ValueError:", e) # ==================================================================== # Пример 4. Платёжная система с валидацией # ==================================================================== from abc import ABC, abstractmethod class InvalidPaymentError(Exception): """Raised when payment amount is not positive.""" pass class PaymentProcessor(ABC): """Abstract base class for payment processors.""" @abstractmethod def pay(self, amount: float) -> None: """Process a payment of the given amount.""" pass @staticmethod def _validate_amount(amount: float) -> None: """Guard clause: ensure amount is positive.""" if amount <= 0: raise InvalidPaymentError("Payment amount must be positive.") class PaypalPayment(PaymentProcessor): def pay(self, amount: float) -> None: self._validate_amount(amount) print(f"Paid {amount} via PayPal.") class CreditCardPayment(PaymentProcessor): def pay(self, amount: float) -> None: self._validate_amount(amount) print(f"Paid {amount} via Credit Card.") payments = [PaypalPayment(), CreditCardPayment()] for payment in payments: try: payment.pay(100) payment.pay(-50) except InvalidPaymentError as e: print("Error:", e) # ==================================================================== # Пример 5. Итератор с нарастающей суммой # ==================================================================== class CumulativeSum: """Iterator yielding running totals.""" def __init__(self, numbers: list[int]) -> None: self.numbers = numbers self.index = 0 self.total = 0 def __iter__(self): return self def __next__(self) -> int: if self.index >= len(self.numbers): raise StopIteration self.total += self.numbers[self.index] self.index += 1 return self.total data = [3, 5, 2, 4] for value in CumulativeSum(data): print(value) # 3 8 10 14