19

私は Python に比較的慣れていないので、言語の機能と、C++ と Java のバックグラウンドから身につけた習慣をうまく調和させるのに苦労しています。

私が抱えている最新の問題は、カプセル化に関係しています。具体的には、Meyer の「Effective C++」の項目 23 によって最もよく要約されているアイデアです。

メンバー関数よりも非メンバー非フレンド関数を優先します

メカニズムの欠如をfriend少し無視して、非メンバー関数は Python のメンバー関数よりも好ましいと見なされますか?

義務的で愚かな例:

class Vector(object):
    def __init__(self, dX, dY):
        self.dX = dX
        self.dY = dY

    def __str__(self):
        return "->(" + str(self.dX) + ", " + str(self.dY) + ")"

    def scale(self, scalar):
        self.dX *= scalar
        self.dY *= scalar

def scale(vector, scalar):
    vector.dX *= scalar
    vector.dY *= scalar

が与えられると、ベクトルの大きさを 2 倍にするまたはをv = Vector(10, 20)呼び出すことができます。v.scale(2)scale(v, 2)

この場合にプロパティを使用しているという事実を考慮して、2 つのオプションのどちらが優れているか (もしあれば)、そしてその理由は?

4

5 に答える 5

4

無料の関数を使用すると、最初のパラメーターにもダックタイピングを使用できる柔軟性が得られます。

メンバー関数は、機能をクラスに関連付ける表現力を提供します。

それに応じて選択してください。通常、関数は同じように作成されるため、クラスのインターフェイスに関してすべて同じ仮定を持つ必要があります。無料の機能を公開すると、その機能scaleが効果的に宣伝され.dX.dYのパブリック インターフェイスの一部になりますVector。それはおそらくあなたが望むものではありません。.dXと を持つ他のオブジェクトで同じ関数を再利用する機能と引き換えに、これを行っています.dY。それはおそらくあなたにとって価値がないでしょう。したがって、この場合、私は確かにメンバー関数を好みます。

無料の関数を好む良い例として、標準ライブラリ以外を探す必要はありません:sortedは無料の関数であり、のメンバー関数ではありませんlist。概念的には、反復可能なシーケンスを並べ替えた結果のリストを作成できるはずだからです。

于 2012-04-09T12:00:32.160 に答える
3

メンバー関数よりも非メンバー非フレンド関数を優先する

これは設計哲学であり、すべてのOOPパラダイムプログラミング言語に拡張でき、拡張する必要があります。これの本質を理解すれば、概念は明確です

クラスのメンバーへのプライベート/保護されたアクセスを必要とせずに実行できる場合、デザインには、クラスのメンバーである関数を含める理由がありません。これを別の方法で考えると、クラスを設計するときに、すべてのプロパティを列挙した後、クラスを作成するのに十分な動作の最小セットを決定する必要があります。使用可能なパブリックメソッド/メンバー関数のいずれかを使用して記述できるメンバー関数は、パブリックにする必要があります。

これはPythonでどのくらい適用できますか

注意すればある程度。Pythonは、特にプライベートメンバーがないため、他のOOP言語(Java / C ++など)と比較して弱いカプセル化をサポートします。(プライベート変数と呼ばれるものがあり、プログラマーは変数名の前に「_」を付けることで簡単に記述できます。これは、名前マングリング機能によってクラスプライベートになります。)したがって、クラスからアクセスする必要があるものと外部からアクセスする必要があるものとの間に薄いようなものがあることを完全に考慮して、文字通りスコットマイヤーの言葉を採用する場合。関数をクラスの不可欠な部分にするかどうかを決定するのは、設計者/プログラマーに任せるのが最善です。簡単に採用できる設計原則の1つ、"Unless your function required to access any of the properties of the class you can make it a non-member function".

于 2012-04-09T12:21:24.747 に答える
2

scaleベクトルのメンバーごとの乗算に依存しているため、乗算をメソッドとして実装し、より一般的に定義することを検討しscaleます。

class Vector(object):
    def __init__(self, dX, dY):
        self._dX = dX
        self._dY = dY

    def __str__(self):
        return "->(" + str(self._dX) + ", " + str(self._dY) + ")"

    def __imul__(self, other):
        if other is Vector:
            self._dX *= other._dX
            self._dY *= other._dY
        else:
            self._dX *= other
            self._dY *= other

        return self

def scale(vector, scalar):
    vector *= scalar

したがって、カプセル化が維持されている間、クラス インターフェイスは豊富で合理化されています。

于 2014-05-07T18:59:50.427 に答える
2

独自の例を見てください。非メンバー関数は、Vector クラスのデータ メンバーにアクセスする必要があります。これはカプセル化の勝利ではありません。これは、渡されたオブジェクトのデータ メンバーを変更する場合に特に当てはまります。この場合、スケーリングされたベクトルを返し、元のベクトルを変更しない方がよい場合があります。

さらに、非メンバー関数を使用したクラス ポリモーフィズムの利点を理解することはできません。たとえば、この場合、2 つのコンポーネントのベクトルしか処理できません。ベクトル乗算機能を利用するか、コンポーネントを反復処理する方法を使用するとよいでしょう。

要約すれば:

  1. メンバー関数を使用して、制御するクラスのオブジェクトを操作します。
  2. 非メンバー関数を使用して、それ自体がポリモーフィックなメソッドと演算子に関して実装されている純粋に汎用的な操作を実行します。
  3. オブジェクトのミューテーションをメソッドに保持する方がおそらく良いでしょう。
于 2012-04-09T11:04:47.173 に答える