💻 Примеры: итоговые сценарии

⚡ Кратко

Сначала запустите ключевые примеры без изменений, затем поменяйте входные данные и объясните получившийся результат.

Пример 1. Абстрактный класс

from abc import ABC, abstractmethod

class Employee(ABC):
    """Абстрактный базовый класс для сотрудников."""

    @abstractmethod
    def work(self) -> None:
        """Основная деятельность сотрудника."""
        pass

    def take_break(self) -> None:
        print("Перерыв на кофе.")


class Programmer(Employee):
    def work(self) -> None:
        print("Пишу код.")


class Manager(Employee):
    def work(self) -> None:
        print("Планирую задачи.")


if __name__ == "__main__":
    for person in (Programmer(), Manager()):
        person.work()
        person.take_break()

Пример 2. Пользовательское исключение с дополнительным полем

class AccessDeniedError(Exception):
    """Вызывается, если возраст недостаточен для доступа."""

    def __init__(self, age: int):
        self.age = age
        super().__init__(f"Access denied: age {age} is too low")


def check_age(age: int) -> None:
    if age < 18:
        raise AccessDeniedError(age)
    print("Access granted")


if __name__ == "__main__":
    try:
        check_age(15)
    except AccessDeniedError as e:
        print("Error:", e)
        print("Age:", e.age)

Пример 3. Контейнер с магическими методами

class Notes:
    """Коллекция заметок с ключами в нижнем регистре."""

    def __init__(self) -> None:
        self._data: dict[str, str] = {}

    def __getitem__(self, key: str) -> str:
        return self._data[key.lower()]

    def __setitem__(self, key: str, value: str) -> None:
        if not value.strip():
            raise ValueError("Empty notes are not allowed")
        self._data[key.lower()] = value

    def __contains__(self, key: str) -> bool:
        return key.lower() in self._data

    def __len__(self) -> int:
        return len(self._data)

    def __str__(self) -> str:
        lines = [f"- {k}: {v}" for k, v in self._data.items()]
        return "Notes:\n" + "\n".join(lines)


if __name__ == "__main__":
    notes = Notes()
    notes["Idea"] = "Build a game"
    notes["TODO"] = "Finish the project"
    print(notes["idea"])
    print("todo" in notes)
    print(len(notes))
    print(notes)

Пример 4. Арифметические операторы

4.1. Сложение векторов

class Vector:
    def __init__(self, x: float, y: float) -> None:
        self.x = x
        self.y = y

    def __add__(self, other: "Vector") -> "Vector":
        if not isinstance(other, Vector):
            return NotImplemented
        return Vector(self.x + other.x, self.y + other.y)

    def __str__(self) -> str:
        return f"({self.x}, {self.y})"


if __name__ == "__main__":
    a = Vector(2, 3)
    b = Vector(1, 4)
    print(a + b)

4.2. Инкрементный счётчик

class Counter:
    def __init__(self, value: int = 0) -> None:
        self.value = value

    def __iadd__(self, other: int) -> "Counter":
        self.value += other
        return self

    def __str__(self) -> str:
        return f"Counter({self.value})"


if __name__ == "__main__":
    c = Counter(5)
    c += 3
    print(c)

Пример 5. __call__ и __bool__

class CurrencyConverter:
    """Объект-конвертер валют."""

    def __init__(self, rate: float) -> None:
        self.rate = rate

    def __call__(self, dollars: float) -> float:
        return dollars * self.rate


class Counter:
    def __init__(self, value: int) -> None:
        self.value = value

    def __bool__(self) -> bool:
        return self.value > 0


if __name__ == "__main__":
    euro = CurrencyConverter(0.88)
    print(euro(10))
    print(euro(5.5))

    c1 = Counter(-5)
    c2 = Counter(3)
    print(bool(c1), bool(c2))
    if c2:
        print("Есть элементы")
    if not c1:
        print("Пусто")

Пример 6. Сравнение через @total_ordering

from functools import total_ordering

@total_ordering
class Book:
    def __init__(self, title: str) -> None:
        self.title = title

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, Book):
            return NotImplemented
        return self.title == other.title

    def __lt__(self, other: "Book") -> bool:
        return self.title < other.title

    def __repr__(self) -> str:
        return f"Book({self.title!r})"


if __name__ == "__main__":
    b1 = Book("1984")
    b2 = Book("1984")
    b3 = Book("Brave New World")
    print(b1 == b2)
    print(b1 < b3)
    print(b1 >= b3)
    print(sorted([b3, b1, b2]))