我有一个Python模块,其中包含许多类,每个类表示具有其属性的特定物理材料(例如,密度,比热)。一些属性只是该类的float
成员,但很多属性取决于某些参数,例如温度。我通过@staticmethod
实现了这一点,即所有类看起来都是
class Copper(object):
magnetic_permeability = 1.0
@staticmethod
def density(T):
return 1.0 / (-3.033e-9 + 68.85e-12*T - 6.72e-15*T**2 + 8.56e-18*T**3)
@staticmethod
def electric_conductivity(T, p):
return 1.0141 * T**2 * p
@staticmethod
def specific heat(T):
return ...
class Silver(object):
...
class Argon(object):
...
...
Class
因此仅仅充当所有数据的容器,@staticmethod
s的丰富让我怀疑这个用例可能有更合适的设计模式。
任何提示?
答案 0 :(得分:5)
我怀疑更合适的结构是Material
类,它将函数或系数作为参数,例如。
class Material(object):
def __init__(self, mag_perm, density_coeffs, ...):
self.mag_perm = mag_perm
self._density_coeffs = density_coeffs
...
def density(self, T):
x0, x1, x2, x3 = self._density_coeffs
return 1.0 / (x0 + (x1 * T) + (x2 * (T ** 2)) + (x3 * (T ** 3)))
然后,每种材料为每个计算出的参数提供自己的系数:
copper = Material(1.0, (-3.033e-9, 68.85e-12, 6.72e-15, 8.56e-18), ...)
copper.density(300)
如果您需要更复杂的关系(例如,不同的计算),您可以使用Material
的子类并重载相应的计算。
答案 1 :(得分:4)
您可以为模块命名copper
并将所有这些命名为模块级功能,然后import copper; copper.density(0)
。
但是,如果有人from copper import density
,并且您还有一个名为cobalt
的模块,另一个名为carbon
,另一个名为chlorine
等,则所有人都拥有自己的density
{1}}功能?哦,哦。
从we're all consenting adults here开始,您可以对此进行记录,并希望您的用户能够很好地了解该模块。或者你可以采取你的方法;在这种情况下,我会考虑将所有元素放在一个名为elements
的模块中,然后用户可以from elements import Copper
。那么静态方法就是合适的。
答案 2 :(得分:2)
定义静态方法实际上总是一个错误。 Python具有函数,因此您始终只需定义模块级函数。 (您有copper.py
,其内部有一个普通的def density(T):
,而不是使用静态方法。)
也就是说,copper.py
看起来像
magnetic_permeability = 1.0
def density(T):
return 1.0 / (-3.033e-9 + 68.85e-12*T - 6.72e-15*T**2 + 8.56e-18*T**3)
def electric_conductivity(T, p):
return 1.0141 * T**2 * p
def specific heat(T):
return ...
在这种特殊情况下,你真的有多种材料吗?如果是这样,那么您可能希望它们是实例,而不是类或模块。如果您不希望它们都具有相同的热量密度依赖的有理立方形式,您可以创建一个子类并拥有该实例,或者您可以创建一个接受函数作为参数的类。
class Material(object):
def __init__(self, density, electric conductivity):
self.density = density
self.electric_conductivity = electric_conductivity
copper = Material(
density=lambda T: 1.0 / (-3.033e-9 + 68.85e-12*T -
6.72e-15*T**2 + 8.56e-18*T**3),
electric_conductivity=lambda T, p: 1.0141 * T**2 * p
)
如果要保持声明式样式,也可以创建元类。
顺便说一下
class Copper():
def __init__(self):
self.magnetic_permeability = 1.0
...
可能不会做你想做的事。这使magnetic_permeability
只能在copper
的实例中访问。我建议不要使用类而不是实例或模块,但是如果你这样做了,你需要做
class Copper(object):
magnetic_permeability = 1.0
...
能够Copper.magnetic_permeability
请注意,我继承了对象,以便我们使用Python 2"新的样式类"。这些变化是微妙的,但如果你确保你永远不会碰到它们,那就更好了。
答案 3 :(得分:1)
这真是一个“尝试季节”的问题。你可以像你所做的那样 - 一个类上的方法或者你可以完全消除这个类,并且只使用模块级函数。一般来说,我更喜欢阅读/理解的更简单的方法。维护。
严格基于您分享的有限示例 - 我倾向于模块级功能。但当然,一个更加充实的例子可能会改变这种观点。
答案 4 :(得分:1)
如何创建将所有必需值作为参数的变量属性函数?
def density(T):
<some function of T>
def electrical_conductivity(T, p):
<some function of T and p>
def some_other_property(T, magnetic_permeability):
<some function of T and magnetic permeability>
然后,可以通过字典定义固定属性。
copper_fixed_properties = {'magnetic_permeability': 1, ...}
您可以通过以下方式使用它:
copper_some_other_property = some_other_property(T, copper.magnetic_permeability)