2

私はいくつかの衝突検出を行っていますが、2つの異なるコンテキストで同じ関数を使用したいと思います。ある文脈では、私はそれが次のようなものになりたいです

def detect_collisions(item, others):
    return any(collides(item, other) for other in others)

そして別の中で、私はそれがなりたいです

def get_collisions(item, others):
    return [other for other in others if collides(item, other)]

ここに2つの関数を書くというアイデアは本当に嫌いです。名前をまっすぐに保つことは1つのターンオフであり、衝突検出へのインターフェースを複雑にすることは別のことです。だから私は考えていました:

def peek(gen):
    try:
        first = next(gen)
    except StopIteration:
        return False
    else:
        return it.chain((first,), gen)

def get_collisions(item, others):
    get_collisions.all = peek(other for other in others if collides(item, other))
    return get_collisions.all

今、私がチェックをしたいとき、私は言うことができます:

if get_collisions(item, others):
    # aw snap

また

if not get_collisions(item, others):
    # w00t

そして、私が実際にそれらを調べたい他の文脈では、私は次のことができます:

if get_collisions(item, others):
    for collision in get_collisions.all:
        # fix it

どちらの場合も、必要以上の処理は行いません。

これは最初の2つの関数よりも多くのコードであると認識していますが、次の利点もあります。

  1. 衝突検出へのインターフェイスを、ノードが中間レベルではなく最上位レベルにあるツリーとして保持します。これはもっと簡単なようです。

  2. 便利なピーク機能で自分自身をフックアップします。もう一度使用すると、実際に記述しているコードは少なくなります。(YAGNIに応えて、持っていればそうします)

それで。あなたが私がどこに住んでいるかを知っていることわざの殺人マニアであるならば、私が上記のコードを書いたならば、私はあなたからの訪問を期待しますか?もしそうなら、あなたはこの状況にどのようにアプローチしますか?

4

2 に答える 2

4

get_collisionsジェネレーターを返すだけです:

def get_collisions(item, others):
    return (other for other in others if collides(item, other))

次に、チェックを実行する場合:

for collision in get_collisions(item, others):
    print 'Collision!'
    break
else:
    print 'No collisions!'
于 2010-10-07T11:52:45.313 に答える
0

これは、 「if ステートメントで代入を書き換える pythonic の方法」で説明したものと非常に似ていますが、このバージョンでは呼び出しごとに 1 つの位置または 1 つのキーワード引数のみを処理するため、キャッシュされた実際の値を常に取得できます ( Python ブール値の True 値かどうか)。

私はあなたの提案が複数のキーワードを受け入れ、すべての結果を通過させたいかどうかに応じて異なる名前の関数を持つことを本当に気にしませんでしany()all()が、単一の関数を2つ以上で使用できるようにするキーワード引数を使用するというアイデアは好きでした同時にスポットします。これが私が最終的に得たものです:

# can be called with a single unnamed value or a single named value
def cache(*args, **kwargs):
    if len(args)+len(kwargs) == 1:
        if args:
            name, value = 'value', args[0]  # default attr name 'value'
        else:
            name, value = kwargs.items()[0]
    else:
        raise NotImplementedError('"cache" calls require either a single value argument '
                                  'or a name=value argument identifying an attribute.')
    setattr(cache, name, value)
    return value

# add a sub-function to clear the cache attributes (optional and a little weird)
cache.clear = lambda: cache.func_dict.clear()

# you could then use it either of these two ways
if get_collisions(item, others):
    # no cached value

if cache(collisions=get_collisions(item, others)):
    for collision in cache.collisions:
        # fix them

すべての見苦しい詳細を別の関数に入れることで、何らかの形でコードに影響を与えることはなくget_collisions()、他の場所でも使用できます。

于 2010-10-07T19:54:05.147 に答える