📋 Формулировка задания
Исходное задание из LMS:
Фигуры и площади. Создайте абстрактный класс Shape. В классе должен быть метод area(), который возвращает площадь фигуры. Реализуйте два класса:
Circle, который принимает радиус.Rectangle, который принимает ширину и высоту.
# Пример использования
shapes = [Circle(3), Rectangle(4, 5)]
for shape in shapes:
print(f"Area: {shape.area():.2f}")
Проверка размеров фигур. Доработайте фигуры:
- Добавьте проверку в конструкторы
CircleиRectangle, чтобы значения были положительными. - Если передано отрицательное или нулевое значение, выбрасывайте пользовательское исключение
InvalidSizeError.
🔧 Шаг 0. Подготовка окружения
Это задание использует только стандартную библиотеку Python, поэтому дополнительные пакеты устанавливать не нужно.
.gitignore, единая история, легко переключаться между уроками.
Создайте (или откройте) рабочую папку
В VS Code нажмите Ctrl+K Ctrl+O → выберите или создайте папку python-fundamentals-practice. Это будет корень вашего учебного репозитория.
# Или в терминале VS Code (Ctrl + `):
mkdir python-fundamentals-practice
cd python-fundamentals-practice
Инициализируйте Git-репозиторий (один раз)
Если папка ещё не является git-репозиторием:
git init
# Создайте базовые файлы
echo "# Python Fundamentals — Практические работы" > README.md
echo "venv/" > .gitignore
echo "__pycache__/" >> .gitignore
echo "*.pyc" >> .gitignore
echo ".env" >> .gitignore
git add README.md .gitignore
git commit -m "init: базовая структура репозитория"
Создайте папку для текущего урока
# Структура: oop/lesson-76/
mkdir -p oop/lesson-76
cd oop/lesson-76
Создайте виртуальное окружение (venv)
# Windows (PowerShell / CMD)
python -m venv venv
venv\Scripts\activate
# Mac / Linux
python3 -m venv venv
source venv/bin/activate
После активации в начале строки терминала появится (venv). Все дальнейшие команды выполняйте внутри venv.
Создайте ветку для задания
# Вернитесь в корень репозитория
cd ../../..
# Создайте и переключитесь на ветку
git checkout -b lesson/76-abstract-classes-exceptions
# Отправьте ветку на удалённый репозиторий (если настроен)
git push -u origin lesson/76-abstract-classes-exceptions
Именование веток: lesson/XX-краткое-название. Это позволяет легко находить нужный урок.
🛠️ Шаги выполнения задания
Создайте файл shapes.py
В папке oop/lesson-76/ создайте файл shapes.py.
import math
from abc import ABC, abstractmethod
class InvalidSizeError(ValueError):
"""Raised when a shape dimension is not positive."""
pass
class Shape(ABC):
"""Abstract base class for geometric shapes."""
@abstractmethod
def area(self) -> float:
"""Return the area of the shape."""
pass
class Circle(Shape):
"""A circle defined by its radius."""
def __init__(self, radius: float) -> None:
if radius <= 0:
raise InvalidSizeError(f"Radius must be positive, got {radius}")
self.radius = radius
def area(self) -> float:
return math.pi * self.radius ** 2
class Rectangle(Shape):
"""A rectangle defined by width and height."""
def __init__(self, width: float, height: float) -> None:
if width <= 0 or height <= 0:
raise InvalidSizeError(
f"Width and height must be positive, got {width}x{height}"
)
self.width = width
self.height = height
def area(self) -> float:
return self.width * self.height
if __name__ == "__main__":
shapes = [Circle(3), Rectangle(4, 5)]
for shape in shapes:
print(f"Area: {shape.area():.2f}")
# Проверка ошибки
try:
Circle(-1)
except InvalidSizeError as e:
print("Caught InvalidSizeError:", e)
Проверка в VS Code:
- Убедитесь, что venv активирован.
- Запустите:
python oop/lesson-76/shapes.py. - В терминале должны появиться площади фигур и сообщение об ошибке.
Проверьте, что нельзя создать экземпляр Shape
>>> from shapes import Shape
>>> Shape()
TypeError: Can't instantiate abstract class Shape with abstract method area
Это подтверждает, что Shape действительно абстрактный.
✅ Полное решение
Полное решение приведено в шаге 1. Ниже краткая версия без комментариев:
import math
from abc import ABC, abstractmethod
class InvalidSizeError(ValueError):
pass
class Shape(ABC):
@abstractmethod
def area(self) -> float:
pass
class Circle(Shape):
def __init__(self, radius: float) -> None:
if radius <= 0:
raise InvalidSizeError(f"Radius must be positive, got {radius}")
self.radius = radius
def area(self) -> float:
return math.pi * self.radius ** 2
class Rectangle(Shape):
def __init__(self, width: float, height: float) -> None:
if width <= 0 or height <= 0:
raise InvalidSizeError(f"Width and height must be positive, got {width}x{height}")
self.width = width
self.height = height
def area(self) -> float:
return self.width * self.height
shapes = [Circle(3), Rectangle(4, 5)]
for shape in shapes:
print(f"Area: {shape.area():.2f}")
🧪 Как проверить решение
- Активируйте venv:
venv\Scripts\activate(Windows) илиsource venv/bin/activate(Mac/Linux). - Запустите файл:
python oop/lesson-76/shapes.py. - Проверьте вывод в терминале:
Area: 28.27(площадь круга с радиусом 3).Area: 20.00(площадь прямоугольника 4×5).- Сообщение об
InvalidSizeErrorдляCircle(-1).
- Убедитесь, что
Shape()вызываетTypeError.
🐛 Отладка в VS Code
Если что-то не работает:
- Поставьте точку останова (breakpoint) в методе
__init__илиarea. - Нажмите F5 или выберите «Run → Start Debugging».
- Используйте панель Debug (переменные, стек вызовов, консоль).
- Проверьте Terminal на наличие traceback — Python показывает номер строки с ошибкой.
💾 Сохранение работы
# Добавьте файлы урока
git add oop/lesson-76/
# Сделайте коммит с осмысленным сообщением
git commit -m "lesson-76: абстрактные классы и пользовательские исключения"
# Отправьте на GitHub / GitLab
git push
💡 Советы и типичные ошибки
- Не забудьте
from abc import ABC, abstractmethodи наследованиеShape(ABC). - Вызывайте
super().__init__(...)в пользовательских исключениях, если переопределяете__init__. - Для числа π используйте
math.pi, а не приближённые значения вроде3.14. - Наследуйте
InvalidSizeErrorотValueError, если ошибка связана с некорректным значением.