如何根据 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)
我有一个父类来描述物理实体的经典力学定义。例如,这个父类有属性:name、mass、position、velocity。 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)
另外,我有一个描述行星的子类,它们基本上是物理物体,因此应该继承其抽象物理属性,即:name、mass、 位置、速度。
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 中的子类类型定义基类参数?的主要内容,如果未能解决你的问题,请参考以下文章
基类和子类函数名相同且参数类型一样,基类函数如何被覆盖,还存在吗?存在何处?请详细回答,谢谢~~~~