如何根据 Python 中的子类类型定义基类参数?

Posted

技术标签:

【中文标题】如何根据 Python 中的子类类型定义基类参数?【英文标题】:How to define base class arguments based upon child class type in Python? 【发布时间】:2016-04-15 17:09:41 【问题描述】:

父类:class Body(object)

我有一个父类来描述物理实体的经典力学定义。例如,这个父类有属性:namema​​sspositionvelocity。 p>

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)

另外,我有一个描述行星的子类,它们基本上是物理物体,因此应该继承其抽象物理属性,即:namema​​ss位置速度

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 文件。

有没有办法改变我的子类的初始化以减少冗余?

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

【问题讨论】:

为孩子们实现类方法,他们应该都__init__计算质量。 @jonrsharpe 所以你是说我应该在def __init__(self, name, mass) 之前调用mass = Planet_Mass(name)?这行不通,因为name 尚未定义。 代码在 cmets 中不起作用。只需在 Python 中使用类方法搜索备用构造函数即可。 【参考方案1】:

不要在 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

如果您想更进一步并避免子类的__init__ 中的if 语句,那么您可以将所需的行为放在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,因为通过名称查找物体的质量不需要访问实例(或类)。

【讨论】:

是的,我刚找到您的第一个解决方案。但是,我确实喜欢您针对用户可操作性的第二种解决方案。非常感谢朋友! 您的解决方案有效。但是,是否有办法避免质疑是否为每个子类指定了质量? 是的,我已经添加了一个例子。 这行得通,但我想让_name2mass(name) 不可见。 你不能在 Python 中让事物“不可见”。

以上是关于如何根据 Python 中的子类类型定义基类参数?的主要内容,如果未能解决你的问题,请参考以下文章

基类和子类函数名相同且参数类型一样,基类函数如何被覆盖,还存在吗?存在何处?请详细回答,谢谢~~~~

Java 继承02

创建一个基类方法,根据调用该方法的子类实例化一个新的子类对象

C++ 模板继承。子类应该用固定类型替换基类中的类型

重载覆盖

请解释python面向对象中的继承