Posts: 8,160
Threads: 160
Joined: Sep 2016
(May-05-2020, 05:46 PM)DPaul Wrote: but i don't see a "generic" superclass here with the different formula's for volume etc I agree it's difficult to come with common methods in this case.
Posts: 6,800
Threads: 20
Joined: Feb 2020
Lets say you are writing some sort of geometry learning program. You program can draw a shape and provide a way for the user to change the parameters. It displays characteristics of the shape, or maybe askes a quiz. Your create a base class for all the geometric shapes
As an example:
class Shapes:
def __init__(self):
self.name = None
self.params = None
self.volume_equation = None
self.area_equation = None
def draw(self, rotation):
"""Abstract method for drawing shape on screen"""
raise NotImplementedError('Subclass responsibility')
def volume(self):
"""Calculate volume of shape"""
raise NotImplementedError('Subclass responsibility')
def surface_area(self):
"""Calculate surface area of shape"""
raise NotImplementedError('Subclass responsibility')
class Cube(shape):
def __init__(self, side):
super().__init__(self)
self.name = 'Cube'
self.params = {'Side': side}
self.volume_equation = 'Side^3'
self.area_equation = '6 * Side^2'
def draw(self, rotation):
"""Draw shape"""
# Cube drawing code would go here
def volume(self):
"""Calculate volume of cube"""
return self.params['Side']**3
def surface_area(self):
"""Calculate surface area of shape"""
return 6 * self.params['Side']**2
class RectangularPrism(shape):
def __init__(self, l, w, h):
super().__init__(self)
self.name = 'Rectangular Prism'
self.params = {'Length': l, 'Width': w, 'Height':h}
self.volume_equation = 'Length * Width * Height'
self.area_equation = '2 * (Length * Width + Length * Height + Width * Height'
def draw(self, rotation):
"""Draw shape"""
# Rectangular prism drawing code would go here
def volume(self):
"""Calculate volume of cube"""
return self.params['Length'] * self.params['Width'] * self.params['Height']
def surface_area(self):
"""Calculate surface area of shape"""
return 2 * (self.params['Length'] * self.params['Width'] + \
self.params['Length'] * self.params['Height'] + \
self.params['Width'] * self.params['Height'])
class Geometry3D:
"""Program for exploring 3D geometric shapes"""
shapes = [Cube(5), RectangularPrism(5, 5, 5)]
def select_shape(self)
"""Print list of shapes. Get user selection"""
for i, shape in enumerate(shapes):
print(i, shape.name
return shapes[int(input('Select a shape: '))]
def display_shape(self, shape):
"""Display a shape"""
print(shape.name)
shape.draw(rotation)
print('Volume =', shape.volume_equation)
print('Area = ', shape.area_equation)
def edit_shape(shape)
print('Area = ', shape.area_equation)
for key in shape.params:
shape.params[key] = float(input(key + ':'))
self.display_shape(shape) The idea is that the program knows very little about shapes. Each shape subclass knows how to do all the stuff specific to that shape, and the main application only has to know the attributes common to all shapes. It should be fairly easy to add new features to the program because you don't have to write special code for each shape. If I want to tumble the shape or make it spin the application only has to calculate a location and rotation. The shapes each know how to draw themselves. If I want to add a new shape all I have to do is write a shape class and add the shape to the shape list. Since none of the application is shape dependent, no other code would have to change.
Like nearly all design paradigms, Object Oriented Programming is a tool for managing complexity of large software systems. Done well it can yield amazing results.
Posts: 741
Threads: 122
Joined: Dec 2017
Thanks for the "hierarchical" ideas, which triggered some out-of-the-box thinking.
I need to reflect on this a little, but my goal is to create
an inheritance construction, that makes some sense, however simple.
So probably, i have been looking at this from the wrong angle.
To make it work, it may be better NOT to do classing by shape.
On the top level we have 2D and 3D shapes (forget the tessaract)
Then we have "volumes", "surfaces ", "circonferences" etc.
Then specific shapes.
Or even ,things that need 1 parameter, 2 or 3.
I have some thinking to do.
Paul
Posts: 8,160
Threads: 160
Joined: Sep 2016
Some more ideas - 2D, but easy to convert to 3D
from collections import namedtuple
from math import sqrt
Point = namedtuple('Point', 'x, y')
class Shape:
def __init__(self, points):
self.points = list(points)
@staticmethod
def side(point1, point2):
return sqrt((point1.x-point2.x) ** 2 + (point1.y-point2.y) ** 2)
@property
def circumference(self):
points2 = self.points[1:]
points2.append(self.points[0])
return sum(self.side(point1, point2) for point1, point2 in zip(self.points, points2))
class Triangle(Shape):
def __init__(self, points):
super().__init__(points)
@property
def surface(self):
# not implemented yet
raise NotImplementedError('Triangle.surface is not implemnted yet.')
class Square(Shape):
def __init__(self, points):
super().__init__(points)
@property
def surface(self):
side = self.side(*self.points[:2])
return side * side
p1 = Point(0, 0)
p2 = Point(3, 0)
p3 = Point(4, 0)
p4 = Point(4, 4)
p5 = Point(0, 4)
triangle = Triangle([p1, p2, p5])
square = Square([p1, p3, p4, p5])
print(square.circumference)
print(triangle.circumference)
print(square.side(p1, p3))
print(square.surface)
print(triangle.surface)
Posts: 741
Threads: 122
Joined: Dec 2017
OK, I'll go with a mix of deanhystad and buran's examples.
The only thing is that i don't want to confuse issues,
so introducing decorators, collections and namedtuples and inheritance in one example,
makes it more difficult to explain. On the other hand, that makes it more generic.
Maybe we'll settle for a simple and an advanced example. :-)
Paul
Posts: 8,160
Threads: 160
Joined: Sep 2016
I am really not sure about the purpose of all this (teaching material?)
Why not settle for something that makes it easier and offers more commonality, instead of shape/geometry thing
Posts: 741
Threads: 122
Joined: Dec 2017
(May-06-2020, 07:46 AM)buran Wrote: Why not settle for something that makes it easier and offers more commonality, instead of shape/geometry thing
Oh, I thought it would be a welcome change from "spam" and "eggs" and "foo" examples.
Paul
Posts: 8,160
Threads: 160
Joined: Sep 2016
(May-06-2020, 05:30 PM)DPaul Wrote: Oh, I thought it would be a welcome change from "spam" and "eggs" and "foo" examples. I was thinking more for e.g.
Person -> Employee/Manager or Student/Teacher
Vehicle -> car/track/bike
Publication-> book/newspaper/magazine
Posts: 741
Threads: 122
Joined: Dec 2017
May-07-2020, 10:13 AM
(This post was last modified: May-07-2020, 10:13 AM by DPaul.)
Stubborn as we are, this could be a very simple inheritance case.
The class 'circle', can be used as such (circonf, surface)
Then somebody discovers the formulas for a sphere, and they are not so different from circle.
In order to save time, he inherits from circle and does not have to type the whole formula.
Could this be an acceptable inheritance example? (It seems to give the right answers)
Paul
import math
class circle:
def __init__(self, diameter):
self.r = diameter / 2
self.pi = math.pi
def circonf(self):
cir = 2 * self.pi * self.r
return cir
def surface(self):
sur = self.pi * (self.r ** 2)
return sur # inherits from circle !
from circleclass import circle
class sphere(circle):
def __init__(self,diameter):
circle.__init__(self, diameter)
self.r = diameter / 2
def area(self):
ar = 4 * circle.surface(self)
return ar
def volume(self):
vol = 4 / 3 * circle.surface(self) * self.r
return vol
|