2

私はPythonでこの関数を持っています:

def Rotate_Vector(vector, axis, direction):

ここで、vectorは 3 つの要素のタプル (各要素はデカルト軸上のベクトルの 3 つの座標 x、y、z を表します)、axisは軸の座標、directionは時計回りまたは反時計回りの動きを表す整数です。

入力パラメータが正しいかどうか、関数で制御したい:

  • ベクトルは 3 つの整数のタプルでなければなりません
  • axisは 3 つの整数のタプルでなければならず、可能な値は -1、0、1 でなければなりません
  • 方向は、値が +1 または -1 の整数でなければなりません。

関数でこれらの制御 (要素の型、値、および数) を行う正しい方法を知りたいです。

編集:

は 6 つのケースになる可能性があります: (1,0,0) (-1,0,0) (0,1,0) (0,-1,0) (0,0,1) (0,0,- 1)

4

3 に答える 3

4

簡単に言えば、しないでください。Python はダック タイプなので、必要なことを実行するだけで、それが機能しない場合は問題が発生します。

たとえば、ベクトルを長さ 3 のタプルに制限すると、リストを渡す人はどうなるでしょうか? それが同じ仕事をするなら、なぜ彼らが何を渡すかがあなたにとって重要なのでしょうか?

本当に必要だと感じたら、次のようにしてください。

if direction not in {1, -1}:
    raise ValueError("direction must be +1 or -1")

if not len(vector) == 3:
    raise ValueError("vector must contain 3 values")

等...

ただし、これは、許可ではなく許しを求めるという Python の原則に違反しています。

ここでのより良いオプションは、マジック ナンバーの使用を避けることです。たとえば、追加してから、Vector.FORWARD = +1それらVector.BACKWARD = -1を方向に渡すように人々に伝えます。これでも柔軟性が得られますが、指示に何を使用するかについてのガイダンスが提供されます。繰り返しになりますがnamedtuples、ベクターを作成する際にガイダンスを提供するために、ベクターを提供できます。

また、PEP-8lowercase_with_underscores関数名を推奨しているためRotate_Vector()、プロジェクト内の既存の規則によって強制されない限り、特に適切な関数名ではないことにも注意してください。

于 2012-04-06T21:44:13.833 に答える
3

ユーザーが送信するコンテナのタイプをチェックすることは避けます。他の回答者が指摘したように、これはコードに無用な制限を課し、コードの再利用を妨げます。インターフェイスの観点から考えてみてください。引数がインターフェイスに準拠している限り、コードはそれらで動作し、必要な結果を生成する必要があります。

ただし、このロジックは、課したい 2 つの特定の制約には適用されません。具体的には、axis変数のエントリを配置し{1, 0, -1}、方向変数を配置する必要があります{1, -1}

これらは有効な制約です。私は次のように実装します:

valid_axis_entries = set((1,0, -1))
valid_direction_values = set((1, -1))

def rotate_vector(vec, axis, direction):
    if not all(entry in valid_axis_entries for entry in axis):
        raise SomeErrorCondition

    if direction not in valid_direction_values:
        raise SomeOtherErrorCondition

私が従う一般的なルールは、意味のある入力は飛ぶことを許可し、意味をなさないraise入力のエラーを許可することです。ベクトルにはどのシーケンスも意味がありますが、アルゴリズムによっては、回転軸に意味のあるシーケンス値itertools.isliceはなく、方向の有効な入力ではないことは確かです。アルゴリズムが失敗する原因となることがわかっている条件を検出し、有用なエラー メッセージを表示することは、意味のあるものを送信することを許可するのと同じくらい、コードのユーザーに配慮することです。

また、方向引数を大文字の名前付き変数として保存し、魔法の定数に頼るのではなく、それらを送信するようにユーザーに勧めることをお勧めします。

于 2012-04-06T23:29:01.547 に答える
1

前に述べたように、python はダック タイプであるため、通常どおりに処理を行い、発生した例外をユーザーが処理することを期待します。

コードを単体テストして、すべてが有効な数値で機能することを確認することをお勧めします。これにより、特定の動作に対する信頼が高まり、エラーの可能性のある場所をより簡単に絞り込むことができます。

本当にタイプをチェックしたい場合は、isinstance(direction, int)デバッグ目的でオブジェクトのタイプに関するアサーション (例: ) を使用できますが、これは実際には単なる「貧弱な単体テスト」です。

Pythonの原則(許可ではなく許しを求め、明示的は暗黙的よりも優れています)を使用して、私は次のようにします:

import math

def rotate_vector(vector, axis, direction):
    try:
        x, y, z = vector
    except TypeError:
        raise TypeError("Invalid vector {0}".format(vector))

    valid_axes = {(1,0,0), (-1,0,0), (0,1,0), (0,-1,0), (0,0,1), (0,0,-1)}

    if not axis in valid_axes:
        raise ValueError("Invalid axis {0}".format(axis))

    try:
        ax, ay, az = axis
    except TypeError:
        raise TypeError("Invalid axis {0}".format(axis))

    # do math to rotate the vector
    # rotated = ...

    try:
        # You really only need the sign of the direction
        return math.copysign(rotated, direction)
        # or:
        return rotated * math.copysign(1, direction)
    except TypeError:
        raise TypeError("Invalid direction {0}".format(direction))

あなたは本当に方向のサインだけを気にするので、それを使うだけでエラーチェックをなくすことができます。の特別なケースは0として扱われ1ますValueError

ax/ay/az または x/y/z が実際に必要ない場合は、 and に対して直接操作を実行し、基になる操作で例外を発生させる方がよい場合がvectorありaxisます。これにより、ダックタイピングが可能になります。

編集:(更新axes->axis質問の新しい値について)

于 2012-04-06T22:58:03.880 に答える