Загрузка данных


import json
from typing import List, Union


class Vehicle:
    """Базовый класс для описания транспортного средства[span_3](start_span)[span_3](end_span)."""

    def __init__(
        self, brand: str, model: str, year: int, mileage: int = 0
    ) -> None:
        """Инициализация атрибутов транспортного средства[span_4](start_span)[span_4](end_span)."""
        self.brand: str = brand
        self.model: str = model
        self.year: int = year
        self.__mileage: int = max(0, mileage)  # Приватный атрибут[span_5](start_span)[span_5](end_span)

    @property
    def mileage(self) -> int:
        """Геттер для получения значения приватного пробега[span_6](start_span)[span_6](end_span)."""
        return self.__mileage

    @mileage.setter
    def mileage(self, value: int) -> None:
        """Сеттер с проверкой: запрещает уменьшение пробега[span_7](start_span)[span_7](end_span)[span_8](start_span)[span_8](end_span)."""
        if value < self.__mileage:
            print(
                f"Предупреждение: нельзя уменьшить пробег (текущий: {self.__mileage} км, попытались поставить: {value} км)!"
            )  #[span_9](start_span)[span_9](end_span)
            return
        self.__mileage = value

    def reset_mileage(self) -> None:
        """Сброс пробега в 0 с выводом предупреждения[span_10](start_span)[span_10](end_span)."""
        print(
            f"Внимание: сброс одометра для {self.brand} {self.model}! Старый пробег был: {self.__mileage} км."
        )  #[span_11](start_span)[span_11](end_span)
        self.__mileage = 0

    def drive(self, km: int) -> None:
        """Увеличивает пробег транспортного средства[span_12](start_span)[span_12](end_span)."""
        if km < 0:
            raise ValueError(
                "Количество километов не может быть отрицательным."
            )  #[span_13](start_span)[span_13](end_span)
        self.mileage += km

    def get_info(self) -> str:
        """Возвращает строку с базовой информацией о ТС[span_14](start_span)[span_14](end_span)."""
        return (
            f"{self.year} {self.brand} {self.model}, пробег: {self.mileage} км"
        )  #[span_15](start_span)[span_15](end_span)

    def transport_type(self) -> str:
        """Возвращает тип транспортного средства[span_16](start_span)[span_16](end_span)."""
        return "общий транспорт"  #[span_17](start_span)[span_17](end_span)

    def to_dict(self) -> dict:
        """Преобразует объект в словарь для сериализации в JSON[span_18](start_span)[span_18](end_span)."""
        return {
            "type": "Vehicle",
            "brand": self.brand,
            "model": self.model,
            "year": self.year,
            "mileage": self.mileage,
        }

    @staticmethod
    def from_dict(data: dict) -> "Vehicle":
        """Создает объект Vehicle из словаря[span_19](start_span)[span_19](end_span)."""
        return Vehicle(
            brand=data["brand"],
            model=data["model"],
            year=data["year"],
            mileage=data["mileage"],
        )


class Car(Vehicle):
    """Подкласс легкового автомобиля[span_20](start_span)[span_20](end_span)."""

    def __init__(
        self,
        brand: str,
        model: str,
        year: int,
        fuel_type: str,
        mileage: int = 0,
    ) -> None:
        """Инициализация атрибутов легкового автомобиля[span_21](start_span)[span_21](end_span)."""
        super().__init__(brand, model, year, mileage)
        self.fuel_type: str = fuel_type  #[span_22](start_span)[span_22](end_span)

    def refuel(self, liters: float) -> None:
        """Метод для моделирования заправки авто[span_23](start_span)[span_23](end_span)."""
        print(
            f"Автомобиль {self.brand} {self.model} заправлен на {liters} л. ({self.fuel_type})."
        )  #[span_24](start_span)[span_24](end_span)

    def get_info(self) -> str:
        """Переопределенный метод получения информации о легковом авто[span_25](start_span)[span_25](end_span)."""
        base_info = super().get_info()
        return f"{base_info}, тип топлива: {self.fuel_type}"  #[span_26](start_span)[span_26](end_span)

    def transport_type(self) -> str:
        """Возвращает тип транспортного средства[span_27](start_span)[span_27](end_span)."""
        return "легковой"  #[span_28](start_span)[span_28](end_span)

    def to_dict(self) -> dict:
        """Преобразует объект Car в словарь[span_29](start_span)[span_29](end_span)."""
        data = super().to_dict()
        data["type"] = "Car"
        data["fuel_type"] = self.fuel_type
        return data

    @staticmethod
    def from_dict(data: dict) -> "Car":
        """Создает объект Car из словаря[span_30](start_span)[span_30](end_span)."""
        return Car(
            brand=data["brand"],
            model=data["model"],
            year=data["year"],
            fuel_type=data["fuel_type"],
            mileage=data["mileage"],
        )


class Truck(Vehicle):
    """Подкласс грузового автомобиля[span_31](start_span)[span_31](end_span)."""

    def __init__(
        self,
        brand: str,
        model: str,
        year: int,
        cargo_capacity: float,
        mileage: int = 0,
    ) -> None:
        """Инициализация атрибутов грузовика[span_32](start_span)[span_32](end_span)."""
        super().__init__(brand, model, year, mileage)
        self.cargo_capacity: float = cargo_capacity  #[span_33](start_span)[span_33](end_span)

    def load_cargo(self, tons: float) -> None:
        """Загрузка груза с проверкой превышения грузоподъемности[span_34](start_span)[span_34](end_span)."""
        if tons > self.cargo_capacity:
            print(
                f"Ошибка: Нельзя загрузить {tons} т! Превышена грузоподъёмность ({self.cargo_capacity} т)."
            )  #[span_35](start_span)[span_35](end_span)
        else:
            print(
                f"Успешно загружено {tons} т в грузовик {self.brand} {self.model}."
            )  #[span_36](start_span)[span_36](end_span)

    def get_info(self) -> str:
        """Переопределенный метод получения информации о грузовике[span_37](start_span)[span_37](end_span)."""
        base_info = super().get_info()
        return f"{base_info}, грузоподъёмность: {self.cargo_capacity} т"  #[span_38](start_span)[span_38](end_span)

    def transport_type(self) -> str:
        """Возвращает тип транспортного средства[span_39](start_span)[span_39](end_span)."""
        return "грузовик"  #[span_40](start_span)[span_40](end_span)

    def to_dict(self) -> dict:
        """Преобразует объект Truck в словарь[span_41](start_span)[span_41](end_span)."""
        data = super().to_dict()
        data["type"] = "Truck"
        data["cargo_capacity"] = self.cargo_capacity
        return data

    @staticmethod
    def from_dict(data: dict) -> "Truck":
        """Создает объект Truck из словаря[span_42](start_span)[span_42](end_span)."""
        return Truck(
            brand=data["brand"],
            model=data["model"],
            year=data["year"],
            cargo_capacity=data["cargo_capacity"],
            mileage=data["mileage"],
        )


def deserialize_vehicle(data: dict) -> Vehicle:
    """Вспомогательная функция для восстановлении объектов нужного класса из JSON[span_43](start_span)[span_43](end_span)."""
    v_type = data.get("type")
    if v_type == "Car":
        return Car.from_dict(data)
    elif v_type == "Truck":
        return Truck.from_dict(data)
    return Vehicle.from_dict(data)


if __name__ == "__main__":
    print("=== Задание 1. Базовый класс и объекты ===")
    v1 = Vehicle("Toyota", "Camry", 2024, 45000)  #[span_44](start_span)[span_44](end_span)
    v2 = Vehicle("Ford", "Focus", 2020, 80)  #[span_45](start_span)[span_45](end_span)
    v1.drive(120)  #[span_46](start_span)[span_46](end_span)
    print(v1.get_info())  #[span_47](start_span)[span_47](end_span)
    print(v2.get_info())  #[span_48](start_span)[span_48](end_span)

    print("\n=== Задание 2. Наследование ===")
    car1 = Car("BMW", "X5", 2022, "Бензин", 15000)  #[span_49](start_span)[span_49](end_span)
    truck1 = Truck("Volvo", "FH16", 2021, 20.0, 100000)  #[span_50](start_span)[span_50](end_span)

    car1.refuel(50)  #[span_51](start_span)[span_51](end_span)
    truck1.load_cargo(15.0)  #[span_52](start_span)[span_52](end_span)
    truck1.load_cargo(25.0)  # Проверка превышения грузоподъемности[span_53](start_span)[span_53](end_span)

    print(car1.get_info())  #[span_54](start_span)[span_54](end_span)
    print(truck1.get_info())  #[span_55](start_span)[span_55](end_span)

    print("\n=== Задание 3. Инкапсуляция и свойства ===")
    print(f"Текущий пробег v1: {v1.mileage} км")  #[span_56](start_span)[span_56](end_span)
    v1.mileage = 40000  # Попытка уменьшить пробег -> должно выдать предупреждение[span_57](start_span)[span_57](end_span)
    v1.mileage = 46000  # Успешное увеличение
    print(f"Обновленный пробег v1: {v1.mileage} км")
    v1.reset_mileage()  # Сброс пробега[span_58](start_span)[span_58](end_span)
    print(f"Пробег v1 после сброса: {v1.mileage} км")

    print("\n=== Задание 4. Полиморфизм и список объектов ===")
    fleet: List[Vehicle] = [
        Vehicle("Hyundai", "Solaris", 2019, 60000),
        Car("Audi", "A6", 2023, "Дизель", 12000),
        Truck("KAMAZ", "5490", 2020, 18.0, 150000),
        Car("Tesla", "Model 3", 2024, "Электричество", 5000),
        Truck("MAN", "TGX", 2018, 22.5, 210000),
    ]  #[span_59](start_span)[span_59](end_span)

    for item in fleet:
        print(
            f"[{item.transport_type()}] {item.get_info()}"
        )  # Вызов через полиморфизм[span_60](start_span)[span_60](end_span)

    print("\n=== Задание 5 (Вариант Б). Сохранение состояния в JSON ===")
    filename = "vehicles.json"

    # Сериализация списка объектов в JSON-файл[span_61](start_span)[span_61](end_span)
    json_data = [item.to_dict() for item in fleet]
    with open(filename, "w", encoding="utf-8") as f:
        json.dump(json_data, f, ensure_ascii=False, indent=4)
    print(f"Данные сохранены в файл {filename}")

    # Загрузка и восстановление объектов из JSON-файла[span_62](start_span)[span_62](end_span)
    with open(filename, "r", encoding="utf-8") as f:
        loaded_data = json.load(f)

    restored_fleet = [deserialize_vehicle(item) for item in loaded_data]

    print("\nВосстановленные объекты из JSON:")
    for obj in restored_fleet:
        print(f"({type(obj).__name__}) {obj.get_info()}")