Menu
Coddy logo textTech

Итоги — Калькулятор фигур

Часть раздела Object Oriented Programming путешествия по Python на Coddy — урок 27 из 64.

challenge icon

Задание

Средне

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

Реализуйте необходимые классы в следующих файлах (ищите комментарии TODO в каждом файле):

  • shape.py — Определите абстрактный базовый класс Shape
  • circle.py — Реализуйте класс Circle
  • rectangle.py — Реализуйте класс Rectangle
  • triangle.py — Реализуйте класс Triangle
  • unknownshape.py — Создайте непроизводный класс, демонстрирующий утиную типизацию (duck typing)
  • shapecalculator.py — Реализуйте функциональность калькулятора

Следуйте комментариям TODO в каждом файле для пошагового руководства. Комплексный набор тестов поможет вам понять ожидаемое поведение и убедиться, что ваша реализация правильно обрабатывает все требования.

Шпаргалка

Поскольку контент урока не предоставлен, а есть только инструкции к заданиям, я не могу создать шпаргалку. Шпаргалки должны основываться в первую очередь на теории и концепциях урока, а контент заданий может служить лишь дополнением, если он содержит полезные пояснения, не затронутые в уроке.

Попробуйте сами

from circle import Circle
from rectangle import Rectangle
from triangle import Triangle
from unknownshape import UnknownShape
from shapecalculator import ShapeCalculator
import math

# Обработчик тестовых случаев
test_case = input()

def test_basic_functionality():
    calculator = ShapeCalculator()
    
    # Тест с Circle (Круг)
    circle = Circle(5)
    print(f"Testing {circle}")
    results = calculator.process_shape(circle)
    print(f"Results: {results}")
    print()
    
    # Тест с Rectangle (Прямоугольник)
    rectangle = Rectangle(4, 6)
    print(f"Testing {rectangle}")
    results = calculator.process_shape(rectangle)
    print(f"Results: {results}")
    print()
    
    # Тест с Triangle (Треугольник)
    triangle = Triangle(3, 4, 5)
    print(f"Testing {triangle}")
    results = calculator.process_shape(triangle)
    print(f"Results: {results}")
    print()
    
    # Тест с UnknownShape (утиная типизация)
    unknown = UnknownShape("Custom", 10)
    print(f"Testing {unknown}")
    results = calculator.process_shape(unknown)
    print(f"Results: {results}")

def test_edge_cases():
    calculator = ShapeCalculator()
    
    # Тест с нулевыми значениями
    print("Testing zero values:")
    circle = Circle(0)
    print(f"Circle(0) area: {circle.area()}, perimeter: {circle.perimeter()}")
    
    rectangle = Rectangle(0, 5)
    print(f"Rectangle(0, 5) area: {rectangle.area()}, perimeter: {rectangle.perimeter()}")
    
    # Тест с очень большими значениями
    print("\
Testing large values:")
    large_circle = Circle(1000000)
    print(f"Circle(1000000) area: {large_circle.area():.2e}, perimeter: {large_circle.perimeter():.2e}")
    
    # Тест с десятичными значениями
    print("\
Testing decimal values:")
    decimal_circle = Circle(0.5)
    print(f"Circle(0.5) area: {decimal_circle.area()}, perimeter: {decimal_circle.perimeter()}")
    
    decimal_triangle = Triangle(2.5, 3.5, 4.5)
    print(f"Triangle(2.5, 3.5, 4.5) area: {decimal_triangle.area()}, perimeter: {decimal_triangle.perimeter()}")

def test_inheritance():
    # Создание экземпляров каждой фигуры
    circle = Circle(5)
    rectangle = Rectangle(4, 6)
    triangle = Triangle(3, 4, 5)
    unknown = UnknownShape("Custom", 10)
    
    # Тест отношений наследования
    from shape import Shape
    print(f"Circle is a Shape: {isinstance(circle, Shape)}")
    print(f"Rectangle is a Shape: {isinstance(rectangle, Shape)}")
    print(f"Triangle is a Shape: {isinstance(triangle, Shape)}")
    print(f"UnknownShape is a Shape: {isinstance(unknown, Shape)}")
    
    # Тест доступности методов
    print("\
Method availability:")
    for shape_name, shape_obj in [("Circle", circle), ("Rectangle", rectangle), 
                                ("Triangle", triangle), ("UnknownShape", unknown)]:
        print(f"{shape_name} has area(): {hasattr(shape_obj, 'area')}")
        print(f"{shape_name} has perimeter(): {hasattr(shape_obj, 'perimeter')}")
        print(f"{shape_name} has describe(): {hasattr(shape_obj, 'describe')}")

def test_polymorphism():
    calculator = ShapeCalculator()
    
    # Создание списка различных фигур
    shapes = [
        Circle(5),
        Rectangle(4, 6),
        Triangle(3, 4, 5),
        UnknownShape("Custom", 10)
    ]
    
    print("Testing polymorphic behavior:")
    for i, shape in enumerate(shapes, 1):
        print(f"\
Shape {i}: {shape.__class__.__name__}")
        results = calculator.process_shape(shape)
        print(f"Results: {results}")

def test_duck_typing():
    calculator = ShapeCalculator()
    
    # Создание совершенно нового класса, имеющего необходимые методы
    class CustomDuckShape:
        def __init__(self, name, factor):
            self.name = name
            self.factor = factor
        
        def area(self):
            return self.factor * 3
        
        def perimeter(self):
            return self.factor * 12
        
        def describe(self):
            return f"This is a {self.name} duck-typed shape with area {self.area()} and perimeter {self.perimeter()}"
        
        def __str__(self):
            return f"Custom {self.name} with factor {self.factor}"
    
    # Тест с пользовательской фигурой с утиной типизацией
    duck_shape = CustomDuckShape("DuckTyped", 5)
    print(f"Testing duck typing with: {duck_shape}")
    results = calculator.process_shape(duck_shape)
    print(f"Results: {results}")
    
    # Сравнение с обычной фигурой
    circle = Circle(5)
    print(f"\
Comparing with regular shape: {circle}")
    results = calculator.process_shape(circle)
    print(f"Results: {results}")

def test_invalid_inputs():
    calculator = ShapeCalculator()
    
    try:
        # Тест с отрицательным радиусом
        print("Testing Circle with negative radius:")
        negative_circle = Circle(-5)
        results = calculator.process_shape(negative_circle)
        print(f"Results: {results}")
    except Exception as e:
        print(f"Error with negative circle: {e}")
    
    try:
        # Тест с недопустимым треугольником (стороны, которые не могут образовать треугольник)
        print("\
Testing invalid Triangle (1, 1, 10):")
        invalid_triangle = Triangle(1, 1, 10)  # Нарушает неравенство треугольника
        results = calculator.process_shape(invalid_triangle)
        print(f"Results: {results}")
        # Проверка, дает ли расчет площади допустимый результат
        area = invalid_triangle.area()
        if math.isnan(area) or not isinstance(area, float) or area <= 0:
            print(f"Invalid triangle area: {area}")
    except Exception as e:
        print(f"Error with invalid triangle: {e}")

# Запуск соответствующего теста на основе ввода
if test_case == "basic_functionality":
    test_basic_functionality()
elif test_case == "edge_cases":
    test_edge_cases()
elif test_case == "inheritance":
    test_inheritance()
elif test_case == "polymorphism":
    test_polymorphism()
elif test_case == "duck_typing":
    test_duck_typing()
elif test_case == "invalid_inputs":
    test_invalid_inputs()
else:
    # Тестовый случай по умолчанию
    test_basic_functionality()

Все уроки раздела Object Oriented Programming