Resumen - Calculadora de figuras
Parte de la sección Object Oriented Programming del Journey de Python de Coddy — lección 27 de 64.
Desafío
IntermedioEn este desafío, implementarás un sistema de calculadora de formas que demuestra el polimorfismo.
Implementa las clases requeridas en los siguientes archivos (busca los comentarios TODO en cada archivo):
shape.py- Define la clase base abstractaShapecircle.py- Implementa la claseCirclerectangle.py- Implementa la claseRectangletriangle.py- Implementa la claseTriangleunknownshape.py- Crea una clase no derivada que demuestre el "duck typing"shapecalculator.py- Implementa la funcionalidad de la calculadora
Sigue los comentarios TODO en cada archivo para obtener una guía paso a paso. La suite de pruebas exhaustiva te ayudará a comprender el comportamiento esperado y a asegurar que tu implementación maneje todos los requisitos correctamente.
Hoja de referencia
Dado que no se proporciona contenido de la lección, solo instrucciones de los desafíos, no puedo crear una hoja de trucos. Las hojas de trucos deben basarse principalmente en la teoría y los conceptos de la lección, y el contenido de los desafíos solo debe servir como complemento cuando contenga explicaciones útiles adicionales que no se hayan cubierto en la lección.
Pruébalo tú mismo
from circle import Circle
from rectangle import Rectangle
from triangle import Triangle
from unknownshape import UnknownShape
from shapecalculator import ShapeCalculator
import math
# Manejador de casos de prueba
test_case = input()
def test_basic_functionality():
calculator = ShapeCalculator()
# Prueba con Circle
circle = Circle(5)
print(f"Testing {circle}")
results = calculator.process_shape(circle)
print(f"Results: {results}")
print()
# Prueba con Rectangle
rectangle = Rectangle(4, 6)
print(f"Testing {rectangle}")
results = calculator.process_shape(rectangle)
print(f"Results: {results}")
print()
# Prueba con Triangle
triangle = Triangle(3, 4, 5)
print(f"Testing {triangle}")
results = calculator.process_shape(triangle)
print(f"Results: {results}")
print()
# Prueba con UnknownShape (duck typing)
unknown = UnknownShape("Custom", 10)
print(f"Testing {unknown}")
results = calculator.process_shape(unknown)
print(f"Results: {results}")
def test_edge_cases():
calculator = ShapeCalculator()
# Prueba con valores cero
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()}")
# Prueba con valores muy grandes
print("\
Testing large values:")
large_circle = Circle(1000000)
print(f"Circle(1000000) area: {large_circle.area():.2e}, perimeter: {large_circle.perimeter():.2e}")
# Prueba con valores decimales
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():
# Crear instancias de cada forma
circle = Circle(5)
rectangle = Rectangle(4, 6)
triangle = Triangle(3, 4, 5)
unknown = UnknownShape("Custom", 10)
# Probar relaciones de herencia
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)}")
# Probar disponibilidad de métodos
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()
# Crear una lista de diferentes formas
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()
# Crear una clase completamente nueva que tenga los métodos requeridos
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}"
# Prueba con la forma personalizada de tipo duck-typing
duck_shape = CustomDuckShape("DuckTyped", 5)
print(f"Testing duck typing with: {duck_shape}")
results = calculator.process_shape(duck_shape)
print(f"Results: {results}")
# Comparar con una forma regular
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:
# Prueba con radio negativo
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:
# Prueba con triángulo inválido (lados que no pueden formar un triángulo)
print("\
Testing invalid Triangle (1, 1, 10):")
invalid_triangle = Triangle(1, 1, 10) # Viola la desigualdad triangular
results = calculator.process_shape(invalid_triangle)
print(f"Results: {results}")
# Verificar si el cálculo del área da un resultado válido
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}")
# Ejecutar la prueba apropiada basada en la entrada
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:
# Caso de prueba por defecto
test_basic_functionality()Todas las lecciones de Object Oriented Programming
1Fundamentos de la POO
Archivos externosIntroducción a la POOClases vs ObjetosEl parámetro selfMétodosAtributosMétodo constructor (__init__)Resumen - Calculadora simple4Herencia
Herencia básicaLa función super()Sobrescritura de métodosHerencia múltipleOrden de resolución de métodosResumen - Jerarquía de empleados7Métodos especiales
Introducción a los métodos mágicosSobrecarga de operadoresMétodos mágicos de contenedoresRepaso - Lista personalizada10Patrones de diseño Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón Strategy2Decoradores
Introducción a los decoradoresDecorador propertyDecorador de métodos estáticosDecorador de métodos de clase5Polimorfismo
Sobreescritura de métodos revisitadaDuck TypingClases y métodos abstractosDiseño de interfacesResumen - Calculadora de figuras8Conceptos avanzados de POO
Composición vs. HerenciaMixinsMétodos estáticos y de claseDecoradores de claseGestores de contexto11Patrones de diseño, parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón Composite3Propiedades de clase
Variables de instancia vs de claseDecoradores de propiedadesAtributos privadosResumen - Gestor de cuentas bancarias