6

回転楕円体の長半径と短半径の2つのパラメータに基づいてさまざまな量を計算するPythonスクリプトを作成しています。これを行うために回転楕円体クラスを作成できることに気づきました。しかし、私はオブジェクト指向デザインに不慣れであり、より経験豊富なチャップスが私を助けることができるかどうか疑問に思います。

インスタンスは、長半径と短半径のそれぞれのパラメーターaとbでインスタンス化されるため、クラスを次のように設計しました。

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

計算したい量の1つはボリュームです。回転楕円体の体積は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.

どちらを使用するのが良いですか、そしてその理由は何ですか?一般に、いつメソッドを使用し、いつ属性を使用しますか?普段は気にしないのですが、実装するものがたくさんあるので、今後の参考のためにオブジェクト指向デザインについて考えてみたいと思います。

ありがとう

編集:

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:'回転楕円体'オブジェクトに属性'ボリューム'がありません

私はここで何が間違っているのですか?

また、私のinitメソッドでは、a/bの代わりにself.alpha=self.longax / self.shortaxを使用しましたが、これは何か違いがありますか?片道が望ましいですか?

4

3 に答える 3

9

3 番目のオプションがあります:プロパティを使用して、属性とメソッドの両方を作成します。

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 では、基本クラスを安全に省略できます。

この場合、ボリュームの計算は十分に安価ですが、実際に必要になるまで、プロパティを使用してボリュームの計算を延期することができます。

上記の例では、読み取り専用プロパティを作成しています。ゲッターのみが定義されています。

>>> 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

そのため、インスタンスごとに 1だけ計算する必要があります。Spheroid

何を使用するかは、多くの要因によって異なります。API をどの程度簡単に使用する必要があるか、ボリュームを計算する頻度、作成するSpheroid インスタンスの数など。これらをループで 100 万個作成するが、それらのほんの一握りのボリュームしか必要としない場合で音量を設定する代わりに、プロパティを使用するのが理にかなっています__init__

ただし、クラスが音量に基づいて調整できる場合。たとえば、半径の 1 つを自動的に調整することで、a@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使用しない) 値としてyour を使用しました。()

于 2013-03-20T18:31:32.840 に答える
2

このデータを常に使用しますか?

そうでない場合は、プロパティを使用して遅延計算できます...

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

  @property
  def volume(self):
      if self._volume is None :
           self._volume = 4*pi/3 * self.longax * self.shortax * self.shortax
      return self._volume
于 2013-03-20T18:32:38.260 に答える
1

次の理由により、メソッドとしてボリュームを実装します。

  1. 他の属性から計算できるため、計算するためのスペースを節約できます (これが非常に複雑な計算であり、キャッシュを考慮することができない場合を除きます)。
  2. これはオブジェクトの自然な「特徴」ではありません。たとえば、円の場合、半径は属性ですが面積ではありません (これは実際にはフォーマット定義ではありません)。
  3. ボリュームのようなものは、オブジェクトのファミリーを持ち、それらのそれぞれのボリュームをポリモーフィックな方法で計算したい場合、一種の抽象メソッドです。
于 2013-03-20T18:34:44.720 に答える