2012-02-21 7 views
11

私はたくさんの関数を作成しましたが、それらの中には非常によく似た句が必要ですが、tryやexcept句や関数内に同じコードがたくさんあるのは嫌です。例:繰り返しの試行句と除外句

import sys 
import random 

def foo(): 
    num=random.random() 
    try: 
     if num>0.5: print 'OK' 
     elif num>0.25: raise NameError('Too Small') 
     else: raise KeyboardInterrupt 
    except NameError: 
     print "%s had a NameError" % sys._getframe().f_code.co_name 
    except: 
     print "%s had a different Error" % sys._getframe().f_code.co_name 

def bar(): 
    num=random.random() 
    try: 
     if num>0.8: print 'OK' 
     elif num>0.6: raise NameError('Too Small') 
     else: raise KeyboardInterrupt 
    except NameError: 
     print "%s had a NameError" % sys._getframe().f_code.co_name 
    except: 
     print "%s had a different Error" % sys._getframe().f_code.co_name 

"try"の後のコードは機能が異なりますが、 "except"の後のコードは同じです。私はこれらの例外文を統合して、コードの見た目を窮屈にしないようにしたいと思います。これを行う良い方法はありますか?

+1

例外をキャッチすることは、通常、本当に悪い考えです。実際の問題を隠し、デバッグを難しくします。あなたが知っているすべての例外をキャッチします。あなたがそれらについて知らないのであれば、本当にそれらをキャッチしたいですか? –

+0

それは良い点です。関数が失敗した場合は、移動するスクリプトが必要です。最後の "except"には、例外の名前を含む 'print sys.exc_info()[:2]'が含まれます。これを行うより良い方法はありますか? – crunkchitis

答えて

22

Python Decoratorsです。

例外ブロックは常に同じです。あなたが望むことをするカスタムデコレータを作ってください。これを各関数/メソッドに適用する必要がありますが、重複は避けられます。

def handleError(function): 
    def handleProblems(): 
     try: 
      function() 
     except Exception: 
      print "Oh noes" 
    return handleProblems 


@handleError 
def example(): 
    raise Exception("Boom!") 

デコレータとメソッドを呼び出す適用:

 
>>> 
>>> example() 
Oh noes 
>>> 

あなたは何をするかだけでなく、例外タイプを変更する必要がありますが、あなたはどこ私は行くよのJISTを取得この。

+0

素晴らしい。これに感謝します。 – crunkchitis

+0

@crunkchitisあなたは大歓迎です。 – Finglas

+2

これは良い例ではありません。なぜなら、デコレータは引数を取る関数に対しては機能しないからです。 – user3467349

6

あなたのtryブロック内のコンテンツは面白いものなので、機能に含める必要があります。次に、あなたが望む関数を選択し、例外をラップして呼び出します。例外コードを関数として記述し、選択した関数を引数として渡すこともできます。例えば

def foo(): 
    num=random.random() 
    if num>0.5: print 'OK' 
    elif num>0.25: raise NameError('Too Small') 
    else: raise KeyboardInterrupt 

def bar(): 
    num=random.random() 
    if num>0.8: print 'OK' 
    elif num>0.6: raise NameError('Too Small') 
    else: raise KeyboardInterrupt 

def try_numerics(f): 
    try: 
     f() 
    except NameError: 
     print "%s had a NameError" % sys._getframe().f_code.co_name 
    except: 
     print "%s had a different Error" % sys._getframe().f_code.co_name 

# In your main code... 
if (need_to_run_foo): 
    try_numerics(foo) 
elif (need_to_run_bar): 
    try_numerics(bar) 
2

実際の関数であれば、それらを一般化するのは簡単でしょう。

あなたは

def general(bottom_num, top_num): 
    num=random.random() 
    try: 
    if num>top_num: print 'OK' 
    elif num>bottom_num: raise NameError('Too Small') 
    else: raise KeyboardInterrupt 
    except NameError: 
    print "%s had a NameError" % sys._getframe().f_code.co_name 
    except: 
    print "%s had a different Error" % sys._getframe().f_code.co_name 

1つの一般的な機能を作成することができ、これは繰り返すから、あなたのコードを維持し、試しに対処します:除く:問題

5

上記の答えは、引数を取る関数には適用されません - のために後者の場合、私はあなたがこのような何かをしたいと思います:

def handleError(f): 
    def handleProblems(*args, **kwargs): 
     try: 
      return f(*args, **kwargs) 
     except Exception: 
      print "Oh noes" 
    return handleProblems 

我々はそうのようにそれをテストすることができます。

@handleError 
def addTwo(x, y): 
    print(x + y) 

>>> addTwo(5,5) 
10 
>>> addTwo(5, 's') 
Oh noes 
0

私は最近私のケースでは、私はいくつかのカスタム例外をログに記録するか、さらに例外を発生させる必要があります。私はタイプごとに例外を処理するデコレータメソッドを作成しました。

try: 
    obj.some_method() 
except Exception as e: 
    catch_and_log_exception(e) 


def catch_and_log_exception(e): 
    if isinstance(e, MyConnectionError): 
     print "Connection error : %s." % e.message 
     sys.exit(1) 
    elif isinstance(e, MyConnectionTimeout): 
     print "Connection to server has been timed out. %s" % e.message 
     sys.exit(1) 
    elif isinstance(e, MyException): 
     message = e.explanation if e.explanation else e.message 
     log_error_message(str(message)) 
     print "Failed, please check the logs." 
     sys.exit(1) 
    else: 
     raise e 

願っています!