2

Parent Class: class Body(object)

I have a parent class characterising the classical mechanics definition of a physical body. Such as it is, this parent class has the attributes: name, mass, position, velocity.

from Utilities import *

class Body(object):

  '''
  In classical mechanics a physical body is collection of
  matter having properties including mass, velocity, momentum
  and energy. The matter exists in a volume of three-dimensional
  space called its extension.
  '''

  def __init__(self, name, mass):
    if isinstance(name, str) and isinstance(mass, float):
      #Name
      self.name = name
      #Mass
      self.mass = mass
      #Position record
      self.positions = np.empty(shape = (0, 3), dtype = float)
      #Velocity record
      self.velocities = np.empty(shape = (0, 3), dtype = float)
      pass
    else:
      raise TypeError('Name and mass must be string and float, respectivly.')
    return None

Child Class: class Planet(Body)

Additionally, I have a child class characterising Planets, which are fundamentally physical bodies, and thus should inherit the abstract physical attributes of such, namely: name, mass, position, velocity.

class Planet(Body):
  def __init__(self, name, mass = float):
    self.mass = Planet_Mass(name)
    Body.__init__(self, name, self.mass)

Usage

#Import the necesary modules
from context import Planet
#Instantiate Earth as a massive celestial object
Earth = Planet('Earth')
#Print the mass of the planet [10^24 kg]
print 'The mass of Earth is: ', Earth.mass, ' [10^24 kg]'

Result

The mass of Earth is: 5.97 [10^24 kg]

Problem

Fundamentally, all physical bodies have mass. However, in the context of this simulation, the method by which mass is determined differs between the various child classes of class Body(object), namely: class Planet(Body), class Satellite(Body), etc.

  • In class Planet(Body), mass is determined via Planet_Mass(name), which involves reading through a planetary fact sheet .txt file.
  • In class Satellite(Body), mass is determined via Satellite_Mass(name), which involves reading through a satellite fact sheet .txt file.

Is there anyway to alter the initialisation of my child classes to be less redundant?

Essentially, I would like to remove the necessity of stating self.mass = Planet_Mass(name) in class Planet(Body).

3
  • Implement class methods for the children, they should all __init__ with the calculated mass. Commented Apr 15, 2016 at 17:11
  • @jonrsharpe So you're saying that I should invoke mass = Planet_Mass(name) before def __init__(self, name, mass)? That will not work, as name will not be defined yet. Commented Apr 15, 2016 at 17:18
  • Code doesn't work out in comments. Just google for alternate constructors in Python using class methods. Commented Apr 15, 2016 at 17:20

1 Answer 1

3

Don't accept mass in your Planet class constructor since you're not going to use it.

Don't set self.mass in your Planet class constructor since the parent constructor does it.

class Planet(Body):
    def __init__(self, name):
        Body.__init__(self, name, Planet_Mass(name))

If you do want to accept mass in your Planet class and allow it to override the mass from the lookup table (or maybe some planets aren't in the lookup table), do it like this:

class Planet(Body):
    def __init__(self, name, mass=None):
        if mass is None:
            Body.__init__(self, name, Planet_Mass(name))
        else:
            Body.__init__(self, name, mass)

earth   = Planet("Earth")
trantor = Planet("Trantor", 1.792e25)   # Asimov's Trantor; ~3x Earth mass

If you want to go further and avoid the if statement in your subclasses' __init__ then you can put the desired behavior on the Body class. The basic idea is that you define a method to calculate the mass from the name. On the base class, this method would do nothing. On your subclasses, it gets the mass from the lookup table. Then you don't even need __init__ in your subclasses.

class Body(object):

     def __init__(self, name, mass=None):
         if mass is None:
             mass = self._name2mass(name)
         # followed by the argument checking and attribute setting
         # especially, you must check that mass is not None

     @staticmethod
     def _name2mass(name): return None

class Planet(Body):

     @staticmethod
     def _name2mass(name): return Planet_Mass(name)
     # or just implement Planet_Mass here!

I've used @staticmethod because looking up a body's mass by its name does not require access to the instance (or the class, for that matter).

Sign up to request clarification or add additional context in comments.

5 Comments

Yes, I just came to your first solution. However, I do like your second solution for user manipulability. Thanks a lot mate!
Your solution works. However, is there anyway to avoid questioning whether mass is specified or not for each child class?
Yes, I've added an example of that.
This works, but I want to keep _name2mass(name) invisible.
You can't make things "invisible" in Python.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.