2014-11-02 45 views
2

如何將應用程序與使用庫依賴關係中出現的異常分離開來?在Python中封裝異常

[app] --uses--> [lib] --dependson--> [dependency] 
             // 
    x- <-propagates--o <---throwsexception--'/
    \          /
    `-----needstohandle,soimports-----> --' 

的問題是從真實pip代碼:

  1. 模塊A(REQ/req_set.py)depends on module B
  2. 模塊B(下載)uses module C(請求)
  3. 模塊A imports模塊C to handle exception from C

如何使用en在模塊B中封裝異常?從模塊A中刪除對C的依賴?如何確保原始異常的原因和細節不會丟失?換句話說,我怎樣才能用另一個名字來重新渲染異常呢?

下面的代碼片段確實是需要的,但它的Python 3只:

try: 
    dependency_call() 
except DependencyError as exc: 
    raise LibraryError from exc 

更新:我正在尋找的Python 2兼容的解決方案,在Python 3中添加raise ... from ...,做的伎倆幾乎良好。

更新2:封裝例外的目標是趕上它[lib]和再拋出一個新的一個[app]保存堆棧跟蹤,使調試工具仍然可以步行的代碼(只有人類才能解決the answer by Alex Thornton應該是好的)。

回答

2

您可以參照Exception基類趕上任意例外:

except Exception as exc: 
    raise ApplicationError from exc 

要獲得from成語在Python 2的工作,你就必須圍繞破解你的自定義異常:

class ApplicationError(Exception): 
    def __init__(self, cause, trace): 
     self.cause = cause 
     self.trace = trace 
    def __str__(self): 
     return '{origin}\nFrom {parent}'.format(origin=self.trace, 
               parent=self.cause) 

然後擡起它像這樣:

except Exception, exc: 
    raise ApplicationError(exc) 

它將在提出時打印cause,如果您決定也要捕獲ApplicationError,則該屬性也是可以訪問的屬性。

+1

@techtonik'from'是好的,你只需要定義你自己的'ApplicationError'異常。 – 2014-11-02 12:01:42

+0

看起來是Python 3的東西。對於Python 2,它給出了SyntaxError - https://dpaste.de/SbtT – 2014-11-02 12:11:36

+1

@techtonik:Thornton先生展示他的解決方案的方式看起來像是「全部抓住」,但我確信他只是想提供解決方案並儘可能快地相信,如果不是特定的例外情況,你可以通過重新提起例外來解決「全部」問題。 – 2014-11-02 12:23:48

0

如果我得到你的權利,你想更強烈的分離和消除:

from pip._vendor import requests 

和:

except requests.HTTPError as exc: 

你可以做到這一點通過引入一個不得已的退回處理程序爲所有的 最後except像除外條款:

try:... 
except A: 
... # here all your other exceptions 
except Exception as exc: # the fall-back handler 
    if "HTTPError" in repr(exc): 
     # do whatever you want to do with the (assumed) request.HTTPError 
     # any other Exception with HTTPError in it's repr-string will be 
     # caught here 

回退是,它仍然是一個緊密的耦合,並且明確違反了Demeter的「法則」,因爲您需要知道一些對象的內部物體,它們甚至不在對象組合中。所以從某種意義上來說現在更糟糕了。

+0

雖然它提供瞭解耦,但我的代碼比原來的更糟糕,仍然不提供封裝。另外它消除了靜態分析或類型檢查的能力。 =) – 2014-11-02 11:51:58

+0

我沒有得到你的「封裝」參數。在這種情況下,我不認爲這是一個問題,因爲自定義異常與「封裝」完全相反,因爲它們不隱藏,但通過公開額外的公共接口增加了複雜性。 – 2014-11-02 12:15:42

+0

鏈由'[app] - > [lib] - > [dep]'組成。 '[lib]'應該封裝所有'[dep]'異常,以隱藏這些額外的公共接口。 – 2014-11-02 12:30:47