18

私は最近、switch-case ステートメントをサポートしている言語で使用しないことを推奨する質問を読みました。Python に関する限り、次のような多くのスイッチ ケースの置換を見てきました。

  1. 辞書の使用 (多くのバリアント)
  2. タプルの使用
  3. 関数デコレーターの使用 ( http://code.activestate.com/recipes/440499/ )
  4. ポリモーフィズムの使用 (型チェック オブジェクトの代わりに推奨される方法)
  5. if-elif-else はしごの使用
  6. 誰かが訪問者パターンを推奨しました(おそらく外因性)

さまざまなオプションがあるため、特定のコードに対して何をすべきかを判断するのに少し苦労しています。一般的に、これらの方法のいずれかを選択する基準を学びたいと思います。また、判断に迷った場合の具体的な対処法(選択肢の説明付き)を教えていただければ幸いです。

ここに特定の問題があります:
(1)

def _setCurrentCurve(self, curve):
        if curve == "sine":
            self.currentCurve =  SineCurve(startAngle = 0, endAngle = 14,
            lineColor = (0.0, 0.0, 0.0), expansionFactor = 1,
            centerPos = (0.0, 0.0))
        elif curve == "quadratic":
            self.currentCurve = QuadraticCurve(lineColor = (0.0, 0.0, 0.0))

このメソッドは、メニューから曲線を描くことを選択したことに応答して、 qt-slotによって呼び出されます。上記の方法では、アプリケーションが完了すると合計 4 ~ 7 個の曲線が含まれます。この場合、使い捨ての辞書を使用することは正当化されますか? これを行う最も明白な方法は if-elif-else ですが、それを使用する必要がありますか? すべての曲線クラスが **kargs を使用しているため、ここで **kargs を使用することも検討しています (友人の助けを借りて)。

(2)
この 2 番目のコードは、ユーザーが曲線のプロパティを変更したときに呼び出されるqt-slotです。基本的に、スロットは gui (spinBox) からデータを取得し、適切なカーブ クラスのインスタンス変数に入れます。この場合、再び同じ質問があります - dict を使用する必要がありますか?

これが前述のスロットです-

def propertyChanged(self, name, value):
    """A Qt slot, to react to changes of SineCurve's properties."""
    if name == "amplitude":
        self.amplitude = value
    elif name == "expansionFactor":
        self.expansionFactor = value
    elif name == "startAngle":
        self.startAngle = value
    elif name == "endAngle":
        self.endAngle = value  

参考までに、上記のスロットに接続するためのコードを次に示します -

def _connectToPage(self, page):
    for connectionData in page.getConnectibles():
        self.connect(connectionData["object"],
                    SIGNAL(connectionData["signal"]),
                    lambda value, name = connectionData["property"]:\
                        self.currentCurve.propertyChanged(name, value))
        self.connect(connectionData["object"],
                    SIGNAL(connectionData["signal"]),
                    self.hackedDisplayArea.update) 

- self.endAngle などはコンストラクタで初期化されます。

私の知る限り、dict を選択する理由は高速検索のためです。それはいつ保証されますか?100件以上の場合は?関数が呼び出されるたびに辞書を作成して破棄し続けるのは良い考えですか? 関数の外でこの目的のために dict を構築する場合、他の場所で必要かどうかを確認する必要がありますか? 他の場所で必要ない場合はどうなりますか?

私の質問は、もしあればベストプラクティスは何ですか? 物事を進めるための最善/最もエレガントな方法は何ですか? さらに別の言い方をすると、if-elif-elseをいつ使用するか、他の各オプションをいつ使用するか?

4

7 に答える 7

8

最初の例では、if-else ステートメントに固執します。実際、if-else を使用しない理由がわかりません。

  1. if ステートメントがボトルネックであることを (たとえば profile モジュールを使用して) 見つけます (非常に多くのケースがほとんど実行されない限り、IMO の可能性はほとんどありません)。

  2. 辞書を使用したコードはより明確であり、繰り返しが少なくなります。

私が実際に書き直すあなたの2番目の例

setattr(self, name, value)

(おそらく、無効な名前をキャッチするために assert ステートメントを追加します)。

于 2009-02-27T12:21:10.560 に答える
2

これがユーザー アクション (メニューから何かを選択する) に応答して行われ、予想される選択肢の数が非常に少ないことを考えると、単純な if-elif-else はしごを使用することは間違いありません。

とにかくユーザーが選択を行うことができるのと同じくらい速くしか起こらないので、速度を最適化しても意味がありません。これは「レイトレーサーの内側のループ」の領域ではありません。確かに、ユーザーに迅速なフィードバックを提供することは重要ですが、ケースの数が非常に少ないため、その危険性もありません。

とにかく(より明確で、読みやすさのオーバーヘッドがゼロ)if-ladderは非常に短いため、簡潔さを最適化する意味はありません。

于 2009-02-27T12:27:13.353 に答える
2

辞書の質問について:

私の知る限り、dict を選択する理由は高速検索のためです。それはいつ保証されますか?100件以上の場合は?関数が呼び出されるたびに辞書を作成して破棄し続けるのは良い考えですか? 関数の外でこの目的のために dict を構築する場合、他の場所で必要かどうかを確認する必要がありますか? 他の場所で必要ない場合はどうなりますか?

  1. もう 1 つの問題は保守性です。string->curveFunction ディクショナリを使用すると、メニューをデータ駆動できます。次に、別のオプションを追加するには、別の string->function エントリをディクショナリに配置するだけです (構成専用のコードの一部に存在します)。

  2. エントリが少ない場合でも、「懸念事項を分離」します。_setCurrentCurveコンポーネントのボックスを定義するのではなく、実行時に配線する責任があります。

  3. 辞書を作成し、それを保持します。

  4. 他の場所で使用されていなくても、上記の利点 (配置可能性、保守性) が得られます。

私の経験則は、「ここで何が起こっているのですか?」と尋ねることです。私のコードの各コンポーネントについて。答えが次の形式の場合

...そして...そして...

(「関数のライブラリを定義し、それぞれをメニューの値関連付ける」のように)、分離することを懇願するいくつかの懸念があります。

于 2009-02-27T12:35:44.800 に答える
1

Pythonでは、switchステートメントを置き換える方法を考えないでください。

代わりに、クラスとポリモーフィズムを使用してください。利用可能な各選択肢とそれを1か所に実装する方法(つまり、それを実装するクラス)に関する情報を保持するようにしてください。

そうしないと、それぞれが各選択肢のごく一部を含む場所がたくさんあることになり、更新/拡張はメンテナンスの悪夢になります。

これはまさに、OODが抽象化、情報隠蔽、ポリモーフィズムなどによって解決しようとする種類の問題です。

所有しているオブジェクトのクラスとそのプロパティについて考えてから、それらの周りにオブジェクト指向アーキテクチャを作成します。これにより、「switch」ステートメントが欠落していることを心配する必要がなくなります。

于 2009-02-27T13:23:21.550 に答える
1

公開されている各オプションは、いくつかのシナリオにうまく適合します。

  1. if-elif-else: シンプルさ、明快さ
  2. 辞書: 動的に構成する場合に便利です (特定の機能をブランチで実行する必要があると想像してください)。
  3. タプル: ブランチごとに複数の選択肢がある場合は、if-else よりも単純です。
  4. ポリモーフィズム: オブジェクト指向の自動分岐

Python は可読性と一貫性が重要であり、決定が常に主観的でスタイルに依存する場合でも、常に Python のマントラについて考える必要があります。

./アレックス

于 2009-02-27T12:23:10.493 に答える
1

2番目の例に関してはdfに同意します。最初の例は、特にすべての曲線コンストラクターが同じ型シグネチャ (おそらく *args および/または **kwargs を使用) を持っている場合は、おそらく辞書を使用して書き直そうとします。何かのようなもの

def _setCurrentCurve(self, new_curve):
    self.currentCurve = self.preset_curves[new_curve](options_here)

またはおそらく

def _setCurrentCurve(self, new_curve):
    self.currentCurve = self.preset_curves[new_curve](**preset_curve_defaults[new_curve])
于 2009-02-27T12:27:03.713 に答える