具有仅具有静态方法的类的模块

时间:2014-02-19 14:31:21

标签: python class design-patterns static-methods

我有一个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的丰富让我怀疑这个用例可能有更合适的设计模式。

任何提示?

5 个答案:

答案 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)