📜 Как показано в исходном конспекте
from abc import ABC, abstractmethod
class Employee(ABC):
@abstractmethod
def work(self):
pass
class Programmer(Employee):
def work(self):
print("Write code")
p = Programmer()
p.work()
class AccessDeniedError(Exception):
pass
def check_age(age):
if age < 18:
raise AccessDeniedError("Access denied: age must be at least 18")
print("Access granted")
Что здесь происходит: код рабочий, но не содержит аннотаций типов, docstring и не передаёт дополнительный контекст в исключения.
❌ Почему этот подход может быть не лучшим сейчас
- Без аннотаций типов сложнее понять, какие аргументы ожидает метод.
- Без docstring IDE и
help()не покажут назначение класса. - Исключение без дополнительных полей затрудняет логирование и отладку.
- Дублирование проверок в наследниках увеличивает риск ошибки.
✅ Рекомендуемый современный вариант
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 the employee's daily work."""
pass
class AccessDeniedError(Exception):
"""Raised when a user is too young."""
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 {min_age}")
def check_age(age: int) -> None:
if age < 18:
raise AccessDeniedError(age)
print("Access granted")
Что улучшилось:
- Аннотации типов делают интерфейс очевидным.
- Docstring помогает другим разработчикам и инструментам.
- Исключение несёт контекст (
age,min_age). - f-strings делают сообщения компактнее и читаемее.
🛡️ Guard clauses вместо вложенных if
# Старый стиль: вложенность
class PaypalPayment(PaymentProcessor):
def pay(self, amount):
if amount > 0:
print(f"Paid {amount} via PayPal.")
else:
raise InvalidPaymentError("Amount must be positive")
# Современный стиль: guard clause
class PaypalPayment(PaymentProcessor):
def pay(self, amount: float) -> None:
if amount <= 0:
raise InvalidPaymentError("Amount must be positive")
print(f"Paid {amount} via PayPal.")
Guard clause (охранное условие) сразу выбрасывает исключение при нарушении контракта, а основной код остаётся без лишней вложенности.
🕰️ Когда старый подход ещё можно встретить
Код без type hints и f-strings встречается в legacy-проектах на Python 2.x или ранних версиях Python 3. При миграции стоит:
- Постепенно добавлять аннотации типов.
- Заменять
"%s" % valueи"{}".format(value)на f-strings. - Выделять повторяющуюся валидацию в методы или функции.