Object-Oriented Programming/Polymorphism/Python3

main.py

```"""This program demonstrates use of the Shape, Triangle, Rectangle, and Square classes."""

from polygon import *

triangle = Polygon([3, 4, 5])
print('triangle sides:', triangle.sides)
print('triangle perimeter:', triangle.perimeter)

rectangle = Polygon([4, 2, 4, 2])
print('rectangle sides:', rectangle.sides)
print('rectangle perimeter:', rectangle.perimeter)

square = Polygon([2, 2, 2, 2])
print('square sides:', square.sides)
print('square perimeter:', square.perimeter)

triangle = Triangle(3, 4, 5)
print('triangle sides:', triangle.sides)
print('triangle perimeter:', triangle.perimeter)
print('triangle area:', triangle.area)

rectangle = Rectangle(4, 2)
print('rectangle sides:', rectangle.sides)
print('rectangle perimeter:', rectangle.perimeter)
print('rectangle area:', rectangle.area)

square = Square(2)
print('square sides:', square.sides)
print('square perimeter:', square.perimeter)
print('square area:', square.area)
```

polygon.py

```import math

class Polygon(object):
"""Supports polygon calculations for perimeter and area. """

sides = []

def __init__(self, sides):
"""Creates a Polygon object.

Args:
sides (list of floats): List of lengths of each side.

Raises:
ValueError: If any side is not numeric or not positive.

"""
try:
for side in sides:
side = self._validate_side(side)
self.sides = sides
except:
raise

@property
def perimeter(self):
"""Gets perimeter of the shape.

Returns:
float: Perimeter of the shape.
"""
return sum(self.sides)

def _validate_side(self, side):
"""Validates length of a side.

Args:
side (float): length of a side

Returns:
float: validated length of the side

Raises:
ValueError: If side is not a valid float.
ValueError: If side is not positive.
"""
try:
side = float(side)
except ValueError:
raise ValueError("side must be a float. Received '" + str(side) + "'")
except:
raise

if side <= 0:
raise ValueError(
"side must be positive. Received %f" % side)

return side

class Triangle(Polygon):
def __init__(self, side1, side2, side3):
"""Creates a triangle.

Args:
side1 (float): Length of side 1.
side2 (float): Length of side 2.
side3 (float): Length of side 3.

Raises:
ValueError: If any side is not numeric or not positive.

"""
side1 = self._validate_side(side1)
side2 = self._validate_side(side2)
side3 = self._validate_side(side3)
self.sides = [side1, side2, side3]

@property
def area(self):
"""Gets area of the triangle.

Returns:
float: Area of the triangle.

References:
https://www.mathsisfun.com/geometry/herons-formula.html
"""
s = self.perimeter / 2
a = self.sides[0]
b = self.sides[1]
c = self.sides[2]
area = math.sqrt(s * (s - a) * (s - b) * (s - c))
return area

class Rectangle(Polygon):
def __init__(self, length, width):
"""Creates a rectangle.

Args:
length (float): Length of rectangle.
width (float): Width of rectangle.

Raises:
ValueError: If any side is not numeric or not positive.
"""
length = self._validate_side(length)
width = self._validate_side(width)
self.sides = [length, width, length, width]

@property
def area(self):
"""Gets area of the rectangle.

Returns:
float: Area of the rectangle.

Note:
Allows for lengths and widths to have been entered in any order.
"""
length = self.sides[0]
width = self.sides[1]
if length == width:
width = self.sides[2]
area = length * width
return area

class Square(Polygon):
def __init__(self, side):
"""Creates a square.

Args:
side (float): Length of a side.

Raises:
ValueError: If side is not numeric or not positive.
"""
side = self._validate_side(side)
self.sides = [side, side, side, side]

@property
def area(self):
"""Gets area of the square.

Returns:
float: Area of the square.
"""
side = self.sides[0]
area = side * side
return area
```

Try It

Copy and paste the code above into one of the following free online development environments or use your own Python3 compiler / interpreter / IDE.