python - 属性还是方法?

标签 python class methods attributes

我正在编写一个 python 脚本,它根据两个参数计算各种数量,即椭球体的长半径和短半径。我想到我可以编写一个球体类来执行此操作。但是,我是面向对象设计的新手,想知道你们更有经验的人是否可以帮助我。

一个实例是用参数a和b分别为长半径和短半径实例化的,所以我设计了类如下:

class Spheroid:
  def __init__(self,a,b):
    self.longax  = a
    self.shortax = b

我要计算的数量之一是体积。球体的体积是 4*pi/3 * a * b * b。

我的问题是,我是在我的类中为此定义方法还是属性?

例如我可以定义一个方法:

def Volume(self):
  return 4*pi/3 * self.longax * self.shortax * self.shortax

或者我可以只使用一个属性:

self.volume = 4*pi/3 * self.longax * self.shortax * self.shortax

我也可以将它包含在 init 方法中:

class Spheroid:
  def __init__(self,a,b):
    self.longax  = a
    self.shortax = b
    self.volume = 4*pi/3 * a * b * b.

哪个更好用,为什么?一般来说,什么时候使用方法,什么时候使用属性?我通常不会关心,但我有一大堆这些要实现,我想了解 OO 设计以供将来引用。

谢谢

编辑:

按照 Martijn 的建议实现属性后,我得到了这样的结果:

class Spheroid(object):
  def __init__(self,a,b):
    self.shortax = a
    self.longax  = b
    self.alpha=self.longax/self.shortax

    @property
    def volume(self):
        return (4*np.pi/3) * self.shortax * self.shortax * self.longax

    @property
    def epsilon(self):
        return np.sqrt(1-self.alpha**(-2))

    @property
    def geometricaspect(self):
        return 0.5 + np.arcsin(self.epsilon)*0.5*self.alpha/self.epsilon

    @property
    def surfacearea(self):
        return 4*np.pi*self.shortax**2*self.geometricaspect

我实例化了一个实例 s = Spheroid() 但每当我尝试类似 s.volume 或 s.epsilon 的东西时,我都会得到一个 AttributeError:

AttributeError: 'Spheroid' 对象没有属性 'volume'

我在这里做错了什么?

此外,在我的 init 方法中,我使用 self.alpha = self.longax/self.shortax 而不是 a/b,这有什么区别吗?一种方式更可取吗?

最佳答案

您有第三种选择:通过使用 property 使其既是属性又是方法。 :

class Spheroid(object):
    def __init__(self, a, b):
        self.long  = a
        self.short = b

    @property
    def volume(self):
        return 4 * pi / 3 * self.long * self.short * self.short

您像访问属性一样访问 .volume:

>>> s = Spheroid(2, 3)
>>> s.volume
75.39822368615503

为了使property 描述符正常工作,在Python 2 中您需要确保您的类继承自object;在 Python 3 中,可以安全地省略基类。

在这种情况下,体积的计算足够便宜,但是属性可以让您推迟必须计算体积,直到您真正需要它。

上面的例子创建了一个只读属性;只定义了一个 setter/getter :

>>> s.volume = None
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

您可以轻松缓存属性计算的结果:

class Spheroid(object):
    _volume = None

    def __init__(self, a, b):
        self.long  = a
        self.short = b

    @property
    def volume(self):
        if self._volume is None:
            self._volume = 4 * pi / 3 * self.long * self.short * self.short
        return self._volume

因此您只需为每个 Spheroid 实例计算 一次

您使用什么取决于许多因素;您的 API 需要多容易使用,计算体积的频率,将创建多少 man Spheroid 实例,等等。如果您在一个循环中创建一百万个这样的实例,但只需要它们的音量,使用属性而不是在 __init__ 中设置音量是有意义的。

但是,如果您的类(class)可以根据音量调整;例如,通过自动调整其中一个半径,@property 仍然更有意义:

class Spheroid(object):
    def __init__(self, a, b):
        self.long  = a
        self.short = b

    @property
    def volume(self):
        return 4 * pi / 3 * self.long * self.short * self.short

    @volume.setter
    def volume(self, newvolume):
        # adjust the short radius
        self.short = sqrt(newvolume / (4 * pi / 3 * self.long))

现在您有一个球体,它会在您调整音量时自然地调整它的短属性:

>>> s = Spheroid(2, 1)
>>> s.volume
8.377580409572781
>>> s.volume = 75.39822368615503
>>> s.long, s.short
(2, 3.0)

注意:从技术上讲,任何您使用.name 表示法访问的对象都是一个属性;包括的方法。出于此答案的目的,我将您的 attribute 用作任何未调用的值(名称后不使用 ())。

关于python - 属性还是方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15531852/

相关文章:

python - Pandas:在单独的列中显示嵌套字典值

python - 由于 SSL 证书错误,pip 无法获取 URL

python - pandas Dataframe isna 基于多个条件更新

python - pypokereval 库配置脚本失败,错误代码为 "No python development environments found"

python - 列出给定类的层次结构中的所有基类?

c++ - 指向成员的指针作为模板参数推导

javascript - 有没有办法在 ES6 类上使用内部方法?

python - 更好地理解 __str__ 用法

java - Java方法不断给我: “cannot find symbol” [duplicate]

c# - 基于变量值的动态方法调度