요약 - 도형 계산기
Coddy Python 여정의 Object Oriented Programming 섹션에 포함된 레슨 — 64개 중 27번째.
챌린지
중급이 챌린지에서는 다형성을 보여주는 도형 계산기 시스템을 구현합니다.
다음 파일들에 필요한 클래스들을 구현하세요 (각 파일의 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()
# 0 값으로 테스트
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()