In: Computer Science
Inheritance - Polymorphism
One advantage of using subclasses is the ability to use polymorphism.
The idea behind polymorphism is that several different types of objects can have the same methods, and be treated in the same way.
For example, have a look at the code we’ve included for this problem. We’ve defined Shape as an abstract base class. It doesn’t provide any functionality by itself, but it does supply an interface (in the form of .area() and .vertices() methods) which are meaningful for any type of 2D Shape.
The total_area function makes use of this to calculate the area of any kind of Shape. We’ve provided an example of this with two Square instances.
We want you to write RightAngledTriangle and Rectangle classes which implement this interface.
The constructor for RightAngledTriangle accepts one argument, vertices, being a list of the points of the triangle relative to its origin. The first vertex will be at the right angle.
The constructor for Rectangle accepts width and height.
class Shape():
"""
A representation of a shape.
"""
def __init__(self, origin=(0, 0)):
"""Construct a shape object
Parameters:
origin(tuple<int, int>): origin of the shape
"""
self.origin = origin
def area(self):
"""
(int) Return the area of the shape.
"""
raise NotImplementedError()
def vertices(self):
"""
Return the vertices of the shape.
Return:
list<tuple<int, int>>: The vertices of the shape, as a
list of tuples
representing two dimensional points.
This list may be returned in any order.
"""
raise NotImplementedError()
class Square(Shape):
"""A Square object"""
def __init__(self, side_length, origin=(0, 0)):
"""
Construct a square object
Parameters:
side_length (int): Length of the sides of the square
origin (tuple<int, int>): Coordinate of topleft corner of
square
"""
super().__init__(origin=origin)
self.side_length = side_length
def area(self):
"""
(int) Return the area of the shape.
"""
return self.side_length * self.side_length
def vertices(self):
"""
Return the vertices of the shape.
Return:
list<tuple<int, int>>: The vertices of the shape, as a
list of tuples
representing two dimensional points.
This list may be returned in any order.
"""
x, y = self.origin
return [
(x, y),
(x, y + self.side_length),
(x + self.side_length, y + self.side_length),
(x + self.side_length, y),
]
def total_area(shapes):
"""
Return the total area of the given list of shapes.
Parameters:
shapes (list<Shape>): The list of shapes to sum the area
for.
Return:
int: The total area of the list of shapes, being the sum of the
area of
each individual shape.
"""
area = 0.
for shape in shapes:
area += shape.area()
return area
def outer_bounds(shapes):
"""
Return the outer bounds of the given list of shapes.
Parameters:
shapes (list<Shape>): The list of shapes to return the outer
bounds for.
Return:
tuple<tuple<int, int>, tuple<int, int>>:
The first element of the tuple is the top-left corner of a
rectangle
which could enclose every shape in the given list.
The second element of the tuple is the bottom-right corner of that
same
rectangle.
The top-left corner of the rectangle will be, at minimum, (0, 0).
"""
vertices = []
for shape in shapes:
for vertex in shape.vertices():
vertices.append(vertex)
top_left_x = 0
top_left_y = 0
bottom_right_x = 0
bottom_right_y = 0
for x, y in vertices:
if x < top_left_x:
top_left_x = x
elif x > bottom_right_x:
bottom_right_x = x
if y < top_left_y:
top_left_y = y
elif y > bottom_right_y:
bottom_right_y = y
return (top_left_x, top_left_y), (bottom_right_x, bottom_right_y)
# example usage
# note that total_area doesn't know nor care that we used instances
of Square
shapes = [Square(2), Square(4, origin=(2, 2))]
area = total_area(shapes)
class Shape():
"""
A representation of a shape.
"""
def __init__(self, origin=(0, 0)):
"""Construct a shape object
Parameters:
origin(tuple<int, int>): origin of the shape
"""
self.origin = origin
def area(self):
"""
(int) Return the area of the shape.
"""
raise NotImplementedError()
def vertices(self):
"""
Return the vertices of the shape.
Return:
list<tuple<int, int>>: The vertices of the shape, as a
list of tuples
representing two dimensional points.
This list may be returned in any order.
"""
raise NotImplementedError()
class Square(Shape):
"""A Square object"""
def __init__(self, side_length, origin=(0, 0)):
"""
Construct a square object
Parameters:
side_length (int): Length of the sides of the square
origin (tuple<int, int>): Coordinate of topleft corner of
square
"""
super().__init__(origin=origin)
self.side_length = side_length
def area(self):
"""
(int) Return the area of the shape.
"""
return self.side_length * self.side_length
def vertices(self):
"""
Return the vertices of the shape.
Return:
list<tuple<int, int>>: The vertices of the shape, as a
list of tuples
representing two dimensional points.
This list may be returned in any order.
"""
x, y = self.origin
return [
(x, y),
(x, y + self.side_length),
(x + self.side_length, y + self.side_length),
(x + self.side_length, y),
]
class Rectangle(Shape):
"""A Rectangle object"""
def __init__(self, width, height, origin=(0, 0)):
"""
Construct a rectangle object
Parameters:
width (int): Width of the rectangle
height (int): Height of the rectangle
origin (tuple<int, int>): Coordinate of topleft corner of
rectangle
"""
super().__init__(origin=origin)
self.width = width
self.height = height
def area(self):
"""
(int) Return the area of the shape.
"""
return self.width * self.height
def vertices(self):
"""
Return the vertices of the shape.
Return:
list<tuple<int, int>>: The vertices of the shape, as a
list of tuples
representing two dimensional points.
This list may be returned in any order.
"""
x, y = self.origin
return [
(x, y),
(x, y + self.height),
(x + self.width, y + self.height),
(x + self.width, y),
]
class RightAngledTriangle(Shape):
"""A RightAngledTriangle object"""
def __init__(self, vertices, origin=(0, 0)):
"""
Construct a right angled triangle object
Parameters:
vertices list<tuple<int, int>>: Length of the sides of
the square
origin (tuple<int, int>): Coordinate of topleft corner of
square
"""
super().__init__(origin=origin)
self.vertices = vertices
def area(self):
"""
(int) Return the area of the shape.
"""
return (abs(self.vertices[0][0] + self.vertices[0][1] -
self.vertices[1][0] - self.vertices[1][1]) *
abs(self.vertices[0][0] + self.vertices[0][1] - self.vertices[2][0]
- self.vertices[2][1]))/2
def vertices(self):
"""
Return the vertices of the shape.
Return:
list<tuple<int, int>>: The vertices of the shape, as a
list of tuples
representing two dimensional points.
This list may be returned in any order.
"""
return self.vertices
def total_area(shapes):
"""
Return the total area of the given list of shapes.
Parameters:
shapes (list<Shape>): The list of shapes to sum the area
for.
Return:
int: The total area of the list of shapes, being the sum of the
area of
each individual shape.
"""
area = 0.
for shape in shapes:
area += shape.area()
return area
def outer_bounds(shapes):
"""
Return the outer bounds of the given list of shapes.
Parameters:
shapes (list<Shape>): The list of shapes to return the outer
bounds for.
Return:
tuple<tuple<int, int>, tuple<int, int>>:
The first element of the tuple is the top-left corner of a
rectangle
which could enclose every shape in the given list.
The second element of the tuple is the bottom-right corner of that
same
rectangle.
The top-left corner of the rectangle will be, at minimum, (0, 0).
"""
vertices = []
for shape in shapes:
for vertex in shape.vertices():
vertices.append(vertex)
top_left_x = 0
top_left_y = 0
bottom_right_x = 0
bottom_right_y = 0
for x, y in vertices:
if x < top_left_x:
top_left_x = x
elif x > bottom_right_x:
bottom_right_x = x
if y < top_left_y:
top_left_y = y
elif y > bottom_right_y:
bottom_right_y = y
return (top_left_x, top_left_y), (bottom_right_x, bottom_right_y)
# example usage
# note that total_area doesn't know nor care that we used instances
of Square
shapes = [Square(2), Square(4, origin=(2, 2)), Rectangle(2, 3),
Rectangle(4, 3, origin=(3, 3)),
RightAngledTriangle([(0, 0), (2, 0), (0, 2)])]
area = total_area(shapes)
print('Total area:', area)