web-dev-qa-db-ja.com

「アウトソーシング」例外-デコレータへの処理

多くのtry/exception/finally-clausesは、コードを「醜く」するだけでなく、同様のタスクに同じ例外処理を使用することがよくあります。だから私はそれらを...デコレータに「アウトソーシング」することで冗長性を減らすことを考えていました。

私がこの結論に達する最初の人ではないと確信していたので、私はグーグルでこれを見つけました-imho --ingenious recipe これは複数の例外を処理する可能性を追加しました。

しかし、これ自体が広く知られ、使用されている慣行ではないように思われる理由に驚いたので、私が考慮していなかった側面があるのではないかと思いました。

  1. 例外処理にデコレータパターンを使用するのは偽物ですか、それともずっと見逃していましたか?教えてください!落とし穴は何ですか?

  2. 合理的な方法でそのような例外処理の作成をサポートするパッケージ/モジュールさえありますか?

45
Don Question

コード自体にtry/exception/finallyブロックを保持する最大の理由は、エラー回復が通常関数の不可欠な部分であるためです。

たとえば、独自のint()関数がある場合:

def MyInt(text):
    return int(text)

textを変換できない場合はどうすればよいですか?戻る0Noneを返しますか?

単純なケースがたくさんある場合は、単純なデコレータが便利であることがわかりますが、リンクしたレシピはやりすぎだと思います。たとえば、次のような場合は、考えられる例外ごとに異なる関数をアクティブ化できます。いくつかの異なる例外、いくつかの異なるコードパス)専用のラッパー関数をお勧めします。

単純なデコレータアプローチについての私の見解は次のとおりです。

class ConvertExceptions(object):

    func = None

    def __init__(self, exceptions, replacement=None):
        self.exceptions = exceptions
        self.replacement = replacement

    def __call__(self, *args, **kwargs):
        if self.func is None:
            self.func = args[0]
            return self
        try:
            return self.func(*args, **kwargs)
        except self.exceptions:
            return self.replacement

およびサンプルの使用法:

@ConvertExceptions(ValueError, 0)
def my_int(value):
    return int(value)

print my_int('34')      # prints 34
print my_int('one')     # prints 0
26
Ethan Furman

基本的に、欠点は、呼び出し元のコンテキストで例外を処理する方法を決定できなくなることです(例外を伝播させるだけです)。場合によっては、これにより責任の分離が欠如する可能性があります。

6
Karl Knechtel