Python中的类范围与模块范围属性

时间:2013-05-08 18:42:46

标签: python

我声明了一个类,它使用几个定义为类属性的硬编码常量进行一些计算。所有方法看起来都类似于以下内容:

class IAPWS_1995:
    @staticmethod
    def dAr_ddelta(delta, tau, Delta, theta, psi):
        _dAr_ddelta = \
            sum(IAPWS_1995.n_0 * IAPWS_1995.d_0 * pow(delta, IAPWS_1995.d_0-1) * pow(tau, IAPWS_1995.t_0)) + \
            sum(IAPWS_1995.n_1 * exp(-pow(delta, IAPWS_1995.c_1)) * (pow(delta, IAPWS_1995.d_1-1) * pow(tau, IAPWS_1995.t_1) * (IAPWS_1995.d_1 - IAPWS_1995.c_1*pow(delta, IAPWS_1995.c_1)))) + \
            sum(IAPWS_1995.n_2 * pow(delta, IAPWS_1995.d_2)*pow(tau, IAPWS_1995.t_2) * exp(-IAPWS_1995.alpha_2*(delta-IAPWS_1995.epsilon_2)**2 - IAPWS_1995.beta_2*(tau-IAPWS_1995.gamma_2)**2) * (IAPWS_1995.d_2/delta - 2*IAPWS_1995.alpha_2*(delta-IAPWS_1995.epsilon_2))) + \
            sum(IAPWS_1995.n_3 * (pow(Delta, IAPWS_1995.b_3)*(psi + delta*IAPWS_1995.dpsi_ddelta(psi, delta)) + IAPWS_1995.dDeltab_ddelta(delta, Delta, theta)*delta*psi))
        return _dAr_ddelta

类范围限定符使得代码(甚至更多)难以阅读。我曾想过做这样的事情来使代码更具可读性:

...
_ = IAPWS_1995
_dAr_ddelta = \
    sum(_.n_0 * _.d_0 * pow(delta, _.d_0-1) * pow(tau, _.t_0)) + \
...

但是,如果我将常量声明移动到模块范围,我根本不需要范围限定符。

是否有理由更喜欢在模块中声明类中的常量(例如,如果将来我有类似的类IAPWS_2014,则命名空间冲突?)

2 个答案:

答案 0 :(得分:1)

如果你将来有类似的(也许是现代化的)课程,e。 G。 IAPWS_2014),考虑使用classmethod而不是staticmethod是有道理的:

class IAPWS_1995(object):
  n_3 = 123
  ...  # further class data

  @classmethod
  def dAr_ddelta(c, delta, tau, Delta, theta, psi):
    _dAr_ddelta = \
        sum(c.n_0 * c.d_0 * pow(delta, c.d_0-1) * pow(tau, c.t_0)) + \
        sum(c.n_1 * exp(-pow(delta, c.c_1)) * (pow(delta, c.d_1-1) * pow(tau, c.t_1) * (c.d_1 - c.c_1*pow(delta, c.c_1)))) + \
        sum(c.n_2 * pow(delta, c.d_2)*pow(tau, c.t_2) * exp(-c.alpha_2*(delta-c.epsilon_2)**2 - c.beta_2*(tau-c.gamma_2)**2) * (c.d_2/delta - 2*c.alpha_2*(delta-c.epsilon_2))) + \
        sum(c.n_3 * (pow(Delta, c.b_3)*(psi + delta*c.dpsi_ddelta(psi, delta)) + c.dDeltab_ddelta(delta, Delta, theta)*delta*psi))
    return _dAr_ddelta

这样,这个类的较新版本可以继承旧版本,只是覆盖实际已更改的变量。如果计算已更改,则不得重新实现:

class IAPWS_2014(IAPWS_1995):
  n_3 = 1234
  ...

关于原始问题的一个更好的副作用是你可以为你喜欢的课程命名参数。 cls可能是典型的(根据PEP8是正典),但c也适用,并且代码与您的_版本一样缩写。

答案 1 :(得分:1)

另一种方法是简单地创建一个名为IAPWS_1995的模块,因为您实际上并没有从类中实例化对象。您的模块看起来像:

n_0, n_1, n_2, n_3 = ...
d_0, d_1, d_2 = ...
t_0, t_1, t_2 = ...
c_1, = ...
b_3, = ...
alpha_2, beta_2, gamma_2, epsilon_2 = ...
dpsi_ddelta = ...
dDeltab_ddelta = ...

def dAr_ddelta(delta, tau, Delta, theta, psi):
    _dAr_ddelta = (
        sum(n_0 * d_0 * pow(delta, d_0-1) * pow(tau, t_0)) +
        sum(n_1 * exp(-pow(delta, c_1)) * (pow(delta, d_1-1) * pow(tau, t_1) * (d_1 - c_1*pow(delta, c_1)))) +
        sum(n_2 * pow(delta, d_2)*pow(tau, t_2) * exp(-alpha_2*(delta-epsilon_2)**2 - beta_2*(tau-gamma_2)**2) * (d_2/delta - 2*alpha_2*(delta-epsilon_2))) + \
        sum(n_3 * (pow(Delta, b_3)*(psi + delta*dpsi_ddelta(psi, delta)) + dDeltab_ddelta(delta, Delta, theta)*delta*psi)))
        return _dAr_ddelta

将常量作为模块级变量,将类方法作为模块级函数。

其他代码可以像这样使用它:

import IAPW2_1995

x = IAPW2_1995.dAr_ddelta( arg1, arg2, arg3, arg4, arg5 )