Python Forum
Inheritance problem - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: Inheritance problem (/thread-26543.html)

Pages: 1 2


RE: Inheritance problem - buran - May-05-2020

(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.


RE: Inheritance problem - deanhystad - May-05-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.


RE: Inheritance problem - DPaul - May-06-2020

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


RE: Inheritance problem - buran - May-06-2020

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)



RE: Inheritance problem - DPaul - May-06-2020

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


RE: Inheritance problem - buran - May-06-2020

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


RE: Inheritance problem - DPaul - May-06-2020

(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. Wink
Paul


RE: Inheritance problem - buran - May-06-2020

(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


RE: Inheritance problem - DPaul - May-07-2020

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