2012-02-21 66 views
11

我創建了一堆函數,我需要非常相似,除了在所有這些子句中,但我討厭有這麼多行的嘗試和除了子句和每個函數內部相同的代碼。例如:重複嘗試和除了子句

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 

該代碼後「嘗試」是功能不同,但之後的碼「除」是相同的。我想合併那些除了語句,所以他們不會讓我的代碼看起來如此擁擠。有沒有一個好的方法來做到這一點?

+1

捕捉任何異常通常是一個非常糟糕的主意。它掩蓋真正的問題並使調試更加困難。捕捉你所知道的任何異常 - 如果你不瞭解它們,你真的想捕捉它們嗎? – 2012-02-21 23:57:17

+0

這是一個很好的觀點。如果該功能失敗,我確實需要腳本繼續前進。最後一個「except」包含'print sys.exc_info()[:2]',其中包含異常的名稱。有一個更好的方法嗎? – crunkchitis 2012-02-22 14:10:27

回答

22

Python Decorators是你想要的。

你說的except塊總是一樣的。做一個自定義的裝飾器,做你想要的。您必須將其應用於每個函數/方法,但它確實可以節省重複。

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 2012-02-22 14:13:16

+0

@crunkchitis你不客氣。 – Finglas 2012-02-22 17:08:13

+2

這不是一個好例子,因爲裝飾器不能用於接受參數的函數。 – user3467349 2014-07-12 10:00:25

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 

,這將讓你的代碼重複和解決的嘗試:除了:問題

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 

希望這個幫助!