🏠 Домашнее задание

⚡ Суть задания

Создать два класса: Email (сравнение по дате, строковое представление, длина, проверка на пустоту) и Money (сложение/вычитание через операторы, строковый формат $amount).

Результат: файл homework_78.py, который можно запустить в VS Code и получить ожидаемый вывод.

📋 Формулировка задания

Исходное задание из LMS:

1. Электронное письмо

Реализуйте класс Email, который представляет электронное письмо. Каждое письмо должно содержать:

  • sender — адрес отправителя;
  • recipient — адрес получателя;
  • subject — тема письма;
  • body — текст письма;
  • date — дата отправки.

Класс должен поддерживать:

  • сравнение писем по дате;
  • преобразование письма в строку;
  • получение длины текста письма;
  • проверку на наличие текста в письме или не состоит ли текст только из пробелов.

Пример использования:

e1 = Email("alice@example.com", "bob@example.com",
           "Meeting", "Let's meet at 10am", datetime(2024, 6, 10))
e2 = Email("bob@example.com", "alice@example.com",
           "Report", "", datetime(2024, 6, 11))
print(e1)
print(e2)
print("Length:", len(e1))
print("Has text:", bool(e1))
print("Is newer:", e2 > e1)

Пример вывода:

From: alice@example.com
To: bob@example.com
Subject: Meeting
- Let's meet at 10am -
From: bob@example.com
To: alice@example.com
Subject: Report
-  -
Length: 18
Has text: True
Is newer: True

2. Класс для работы с деньгами

Создайте класс Money, в котором можно:

  • складывать и вычитать объекты через операторы + и -;
  • выводить объект как строку в виде $<amount>;
  • при сложении и вычитании возвращается новый объект;
  • если вычитание приводит к отрицательному значению — вернуть 0.

Пример использования:

money1 = Money(100)
money2 = Money(50)
print(money1 + money2)
print(money1 - money2)
print(money2 - money1)

Пример вывода:

$150
$50
$0

🔧 Шаг 0. Подготовка окружения

Перед началом работы над любым заданием курса нужно настроить окружение.

1

Создайте папку для текущего урока

Внутри учебного репозитория python-fundamentals-practice создайте папку lesson-78.

mkdir -p lesson-78
cd lesson-78
2

Создайте виртуальное окружение (venv)

# Windows
python -m venv venv
venv\Scripts\activate

# Mac / Linux
python3 -m venv venv
source venv/bin/activate

После активации в начале строки терминала появится (venv).

3

Создайте ветку для задания

cd ..
git checkout -b lesson/78-magic-methods

Именование веток: lesson/XX-краткое-название.

🛠️ Шаги выполнения задания

1

Создайте файл homework_78.py

В папке lesson-78 создайте файл homework_78.py.

2

Реализуйте класс Email

  • Сохраните пять полей из условия.
  • __str__ должен формировать вывод из четырёх строк: From:, To:, Subject: и - {body} -.
  • __len__ возвращает длину body.
  • __bool__ возвращает True, если body не пустое и не состоит из пробелов.
  • Для сравнения по дате используйте @total_ordering с __eq__ и __lt__.
3

Реализуйте класс Money

  • __add__ и __sub__ возвращают новый объект Money.
  • В __sub__ результат не должен быть меньше 0.
  • __str__ возвращает строку вида $150.
  • Проверяйте тип other через isinstance.
4

Проверьте работу в VS Code

# В терминале с активированным venv
python lesson-78/homework_78.py

Ожидаемый вывод см. в формулировке задания выше.

✅ Полное решение

Ниже приведено полное решение задания. Совет: попробуйте выполнить самостоятельно, прежде чем смотреть ответ.

from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime
from functools import total_ordering


@total_ordering
@dataclass
class Email:
    sender: str
    recipient: str
    subject: str
    body: str
    date: datetime

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

    def __lt__(self, other: Email) -> bool:
        if not isinstance(other, Email):
            return NotImplemented
        return self.date < other.date

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

    def __bool__(self) -> bool:
        return bool(self.body.strip())

    def __str__(self) -> str:
        return (
            f"From: {self.sender}\n"
            f"To: {self.recipient}\n"
            f"Subject: {self.subject}\n"
            f"- {self.body} -"
        )


@dataclass
class Money:
    amount: int

    def __add__(self, other: Money) -> Money:
        if not isinstance(other, Money):
            return NotImplemented
        return Money(self.amount + other.amount)

    def __sub__(self, other: Money) -> Money:
        if not isinstance(other, Money):
            return NotImplemented
        return Money(max(0, self.amount - other.amount))

    def __str__(self) -> str:
        return f"${self.amount}"


if __name__ == "__main__":
    e1 = Email(
        "alice@example.com",
        "bob@example.com",
        "Meeting",
        "Let's meet at 10am",
        datetime(2024, 6, 10),
    )
    e2 = Email(
        "bob@example.com",
        "alice@example.com",
        "Report",
        "",
        datetime(2024, 6, 11),
    )
    print(e1)
    print()
    print(e2)
    print("Length:", len(e1))
    print("Has text:", bool(e1))
    print("Is newer:", e2 > e1)

    print()
    money1 = Money(100)
    money2 = Money(50)
    print(money1 + money2)
    print(money1 - money2)
    print(money2 - money1)

🧪 Как проверить решение

  1. Активируйте venv: venv\Scripts\activate (Windows) или source venv/bin/activate (Mac/Linux).
  2. Запустите файл: python lesson-78/homework_78.py.
  3. Убедитесь, что вывод совпадает с примером из LMS.
  4. Проверьте, что при вычитании большей суммы из меньшей получается $0.

🐛 Отладка в VS Code

Если что-то не работает:

  1. Поставьте точку останова (breakpoint) кликом слева от номера строки, например на строке def __lt__(self, other: Email) -> bool:.
  2. Нажмите F5 или выберите «Run → Start Debugging».
  3. Используйте панель Debug: проверьте значения полей date и body.
  4. Посмотрите Terminal — Python покажет номер строки с ошибкой и traceback.

💾 Сохранение работы

git add lesson-78/
git commit -m "lesson-78: магические методы — Email и Money"
git push

💡 Советы и типичные ошибки

  • В Money.__sub__ используйте max(0, ...), чтобы не вернуть отрицательную сумму.
  • Email.__bool__ должен смотреть на body.strip(), а не просто на body: строка из пробелов считается пустой.
  • Не забывайте проверять тип other в арифметических методах и возвращать NotImplemented.
  • Не коммитьте папку venv/ — она указана в .gitignore.
Проверить по документации: о формате строк см. f-strings, о dataclasses — dataclasses, о @total_orderingfunctools.total_ordering.