1

getattrメソッドまたは値を動的に取得するために使用する Python のケースを考えてみましょう。

def message(obj, msg, *args, **kwargs):
    result = getattr(obj, msg, None)
    if result is not None:
        try:
            return result(*args, **kwargs)
        except TypeError:
            return result

...ただ、ちょっと待ってください。それはあまり良い振る舞いではありません。これが不適切なgetattr呼び出しであったとしても、暗黙的に None が返されます。これは、この種の関数にとって必ずしも優れた動作ではありません。

(とにかく私が知っていた) 善良でまともな歩哨に直面して、確かな「私を信じてください、あなたはこれを返したくない」値を決定するために、私getattrは例外。このように、「他の男」がかわいいと決めて、この役に立たない歩哨を属性にしない限り、悪い検索は常に明白で捕らえられるべきです.

class _BadMessageException(Exception):
    pass

def _did_not_find(*args, **kwargs):
    raise BadMessageException

def _raise_right_exception(msg, obj):
    if not isinstance(msg, basestring):
        raise TypeError("Message '{}' was not a string".format(msg))
    else:
        raise AttributeError("Bad message '{}' sent to object '{}'".format(msg, obj))

このように、None を返すとき、メッセージは常に少なくとも上向きになります。また、予想される例外も発生します。そのようなメソッド/ ivar がないオブジェクトの場合は AttributeError、渡された引数が多すぎる場合は TypeError などです。編集:当然、最初に間違ったコード スニペットを投稿します。これが修正された関数です。

def message(obj, msg, *args, **kwargs):
    result = getattr(obj, msg, _did_not_find)
    try:
        return result(*args, **kwargs)
    except TypeError:
        if not args or kwargs:
            return result
        else:
            _raise_right_exception(msg, obj)
    except _BadMessageException:
        _raise_right_exception(msg, obj)

これが正しい方法で失敗することを確認するためだけに、余分なコードがたくさんあるように感じます。半神をなだめるためだけに、優先eafp例外を発生させるためのMcGuffinである例外を発生させる関数...うーん。

戻り値が不明または保証されていないこの状況または他の状況で、有効な「失敗」センチネルを宣言するためのより簡単な構文はありますか?

4

1 に答える 1

2

getattr()デフォルトをまったく指定しないでください。代わりに、値を上げたり、悪い値を指定AttributeErrorしたりTypeErrorします。msg

>>> getattr(object(), 'foo')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute 'foo'
>>> getattr(object(), 42)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: getattr(): attribute name must be string

これにより、メソッドが簡単になります。

def message(obj, msg, *args, **kwargs):
    result = getattr(obj, msg)
    try:
        return result(*args, **kwargs)
    except TypeError:
        return result

または、更新されたバージョンの場合、引数が渡された場合は再レイズとほぼ同じです:

def message(obj, msg, *args, **kwargs):
    result = getattr(obj, msg)
    try:
        return result(*args, **kwargs)
    except TypeError:
        if not args and not kwargs:
            # assume attribute access was desired
            return result
        raise
于 2014-05-19T19:17:00.223 に答える