✅ Решения заданий

⚠️ Рекомендация: попробуйте решить задания самостоятельно, прежде чем смотреть ответы. Решения — это последняя инстанция, когда собственные попытки исчерпаны.

⚡ Кратко

  • Задания 1–4: класс Student с валидацией, счётчиком, __str__ и show_info.
  • Задание 5: @classmethod from_string.
  • Задание 6: calculate_age_on(target_date).
  • Задание 7: @staticmethod filter_by_min_age.
  • Задание 8: демонстрация работы с исключениями и фильтрацией.

Итоговое решение

Ниже приведён полный код, покрывающий все восемь заданий.

from datetime import datetime, date


class Student:
    current_id: int = 1
    MIN_AGE: int = 16

    def __init__(self, name: str, birth_date: str) -> None:
        # Задание 1: парсинг даты и валидация возраста
        self.birth_date = datetime.strptime(birth_date, "%Y-%m-%d").date()
        if not self.is_valid_birthdate():
            raise ValueError("Student must be at least 16 years old.")

        self.name = name

        # Задание 2: автоинкремент student_id
        self.student_id = Student.current_id
        Student.current_id += 1

    # Задание 3: строковое представление
    def __str__(self) -> str:
        return f"Student: {self.name}, birth_date: {self.birth_date}, ID: {self.student_id}"

    def __repr__(self) -> str:
        return (
            f"Student(name={self.name!r}, birth_date={self.birth_date!r}, "
            f"student_id={self.student_id!r})"
        )

    # Задание 4: карточка студента
    def show_info(self) -> None:
        print(
            f"Student:\n\tName: {self.name}\n\tAge: {self.calculate_age()}\n\tID: {self.student_id}"
        )

    def calculate_age(self) -> int:
        today = date.today()
        return self.calculate_age_on(today)

    # Задание 6: возраст на конкретную дату
    def calculate_age_on(self, target_date: date) -> int:
        age = target_date.year - self.birth_date.year
        if (target_date.month, target_date.day) < (self.birth_date.month, self.birth_date.day):
            age -= 1
        return age

    def is_valid_birthdate(self) -> bool:
        return self.calculate_age() >= self.MIN_AGE

    # Задание 5: альтернативный конструктор
    @classmethod
    def from_string(cls, data: str) -> "Student":
        name, date_string = map(str.strip, data.split(","))
        return cls(name, date_string)

    # Задание 7: фильтрация по возрасту
    @staticmethod
    def filter_by_min_age(students: list["Student"], min_age: int) -> list["Student"]:
        return [s for s in students if s.calculate_age() >= min_age]


# Задание 8: проверка работы класса
s1 = Student("Alice", "2005-05-10")
s2 = Student.from_string("Bob, 2001-12-03")

print(s1)
s1.show_info()
print(s2)
s2.show_info()

print("Min age 21:")
for student in Student.filter_by_min_age([s1, s2], 21):
    print("\t", student)

try:
    Student("Bill", "2009-05-15")
except ValueError as error:
    print(f"ValueError: {error}")

Решение 1. Класс Student

Дата парсится через datetime.strptime(...).date(). Валидация возраста вынесена в метод is_valid_birthdate, который вызывается в __init__ до присвоения ID.

Решение 2. Номер студента

Атрибут класса current_id увеличивается на 1 каждый раз, когда успешно создаётся новый объект. Если валидация не проходит, ID не выдаётся.

Решение 3. Строковое представление

__str__ возвращает удобную для чтения строку. __repr__ здесь отличается и показывает, как воссоздать объект.

Решение 4. Карточка студента

Метод show_info использует \t для отступа и вызывает calculate_age(), чтобы получить актуальный возраст.

Решение 5. Альтернативный конструктор

from_string — классовый метод: он получает cls и возвращает cls(name, date_string). Это позволяет создавать объект не из отдельных аргументов, а из одной строки.

Решение 6. Возраст на конкретную дату

Метод calculate_age_on повторяет логику подсчёта возраста, но использует переданную дату вместо date.today().

Решение 7. Фильтрация студентов по возрасту

Статический метод filter_by_min_age не зависит от конкретного объекта. Он получает список студентов и пороговый возраст, возвращая список подходящих.

Решение 8. Проверка работы класса

В финальном блоке создаются два студента разными способами, выводится информация, фильтруется список и ловится ValueError для слишком молодого кандидата.

Ожидаемый вывод (зависит от текущей даты):

Student: Alice, birth_date: 2005-05-10, ID: 1
Student:
	Name: Alice
	Age: 21
	ID: 1
Student: Bob, birth_date: 2001-12-03, ID: 2
Student:
	Name: Bob
	Age: 24
	ID: 2
Min age 21:
	 Student: Bob, birth_date: 2001-12-03, ID: 2
ValueError: Student must be at least 16 years old.
Проверить по документации: аннотации типов и использование list[...] выходят за рамки исходного материала. Подробнее см. typing и mypy.