如何在Python中基于子类类型定义基类参数?

时间:2016-04-15 17:09:42

标签: python python-2.7 class inheritance abstract-class

父类:class Body(object)

我有一个父类,描述了一个物理身体的经典力学定义。例如,这个父类具有以下属性:名称质量位置速度

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

儿童类:class Planet(Body)

此外,我有一个表征行星的子类,它们基本上是物理体,因此应该继承这样的抽象物理属性,即:名称质量位置速度

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

用法

#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]'

结果

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

问题

从根本上说,所有身体都有质量。但是,在此模拟的上下文中,确定质量的方法在class Body(object)的各种子类之间有所不同,即:class Planet(Body)class Satellite(Body),等

  • class Planet(Body)中,质量是通过Planet_Mass(name)确定的,其中包括阅读行星事实表.txt文件。
  • class Satellite(Body)中,质量是通过Satellite_Mass(name)确定的,其中包括阅读卫星情况说明书.txt文件。

无论如何都要改变我的子课程的初始化,以减少冗余?

基本上,我想删除在self.mass = Planet_Mass(name)中陈述class Planet(Body)的必要性。

1 个答案:

答案 0 :(得分:3)

不要在Planet类构造函数中接受mass,因为您不打算使用它。

不要在Planet类构造函数中设置self.mass,因为父构造函数会这样做。

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

如果您确实想接受Planet类中的mass并允许它覆盖来自查找表的质量(或者某些行星不在查找表中),这样做:

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中的__init__语句,那么您可以在Body类上放置所需的行为。基本思想是定义一个从名称中计算质量的方法。在基类上,此方法不执行任何操作。在您的子类上,它从查找表中获取质量。那么你的子类中甚至不需要__init__

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!

我使用了@staticmethod,因为通过名称查找正文的质量不需要访问实例(或类,就此而言)。