簡體   English   中英

如何查找給定庫函數在Python中引發的所有異常列表?

[英]How Can I Find a List of All Exceptions That a Given Library Function Throws in Python?

很抱歉這個長標題,但它似乎對我的問題最具描述性。

基本上,我很難在官方python文檔中找到異常信息。 例如,在我正在編寫的一個程序中,我正在使用shutil libary的move函數:

from shutil import move
move('somefile.txt', '/tmp/somefile.txt')

這工作正常,只要我有/ tmp /的寫訪問權限,就有足夠的磁盤空間,並且滿足所有其他要求。

但是,在編寫通用代碼時,通常很難保證這些因素,因此通常使用異常:

from shutil import move
try:
    move('somefile.txt', '/tmp/somefile.txt')
except:
    print 'Move failed for some reason.'

我想實際捕獲適當的異常拋出而不是只捕獲所有內容 ,但我根本找不到大多數python模塊拋出的異常列表。 有沒有辦法讓我看看給定函數可以拋出哪些異常,為什么? 這樣我可以為每個例外做出適當的案例,例如:

from shutil import move
try:
    move('somefile.txt', '/tmp/somefile.txt')
except PermissionDenied:
    print 'No permission.'
except DestinationDoesNotExist:
    print "/tmp/ doesn't exist"
except NoDiskSpace:
    print 'No diskspace available.'

答案要點是誰可以將我鏈接到一些我在官方文檔中忽略的相關文檔,或者提供一種確定的方法來確定哪些函數拋出了哪些異常,以及為什么。

謝謝!

更新 :從給出的答案看來,確實沒有100%直接的方法來確定特定功能拋出哪些錯誤。 使用元編程,似乎我可以找出簡單的情況並列出一些例外,但這不是一個特別有用或方便的方法。

我想最終會有一些標准來定義每個python函數引發的異常,並且這些信息將包含在官方文檔中。 在那之前,我想我會允許這些異常通過並為我的用戶輸出錯誤,因為這似乎是最理智的事情。

為了放大Messa,抓住你所期望的失敗模式,你知道如何恢復。 Ian Bicking寫了一篇文章 ,與Eli Bendersky的筆記一樣,解決了一些總體原則。

示例代碼的問題在於它處理錯誤,只是對它們進行美化並丟棄它們。 你的代碼並不“知道”如何處理NameError,除了傳遞它之外沒什么應該做的,如果你覺得必須添加細節,請查看Bicking的重新加注。

對於shutil.move ,IOError和OSError是合理的“可預期的”但不一定可以處理。 你的函數的調用者希望它移動一個文件,如果Eli寫的那個“契約”被破壞,它本身可能會破壞。

抓住你可以修復,裝飾和重新提升你期望但無法修復的東西,並讓調用者處理你沒想到的東西,即使“處理”的代碼是main的堆棧中的七個級別。

Python現在沒有一種機制來聲明拋出哪些異常,這與(例如)Java不同。 (在Java中,你必須確切地定義哪些異常被拋出,如果你的一個實用程序方法需要拋出另一個異常,那么你需要將它添加到調用它的所有方法中,這很快就會枯燥!)

因此,如果您想要確切地發現任何給定的python位引發了哪些異常,那么您需要檢查文檔和源代碼。

但是python有一個非常好的異常層次結構。

如果您研究下面的異常層次結構,您將看到要捕獲的錯誤超類稱為StandardError - 這應該捕獲在正常操作中可能生成的所有錯誤。 將錯誤轉換為字符串將為用戶提供關於出錯的合理建議,因此我建議您的上面的代碼應該看起來像

from shutil import move
try:
    move('somefile.txt', '/tmp/somefile.txt')
except StandardError, e:
    print 'Move failed: %s' % e

異常層次結構

BaseException
|---Exception
|---|---StandardError
|---|---|---ArithmeticError
|---|---|---|---FloatingPointError
|---|---|---|---OverflowError
|---|---|---|---ZeroDivisionError
|---|---|---AssertionError
|---|---|---AttributeError
|---|---|---BufferError
|---|---|---EOFError
|---|---|---EnvironmentError
|---|---|---|---IOError
|---|---|---|---OSError
|---|---|---ImportError
|---|---|---LookupError
|---|---|---|---IndexError
|---|---|---|---KeyError
|---|---|---MemoryError
|---|---|---NameError
|---|---|---|---UnboundLocalError
|---|---|---ReferenceError
|---|---|---RuntimeError
|---|---|---|---NotImplementedError
|---|---|---SyntaxError
|---|---|---|---IndentationError
|---|---|---|---|---TabError
|---|---|---SystemError
|---|---|---TypeError
|---|---|---ValueError
|---|---|---|---UnicodeError
|---|---|---|---|---UnicodeDecodeError
|---|---|---|---|---UnicodeEncodeError
|---|---|---|---|---UnicodeTranslateError
|---|---StopIteration
|---|---Warning
|---|---|---BytesWarning
|---|---|---DeprecationWarning
|---|---|---FutureWarning
|---|---|---ImportWarning
|---|---|---PendingDeprecationWarning
|---|---|---RuntimeWarning
|---|---|---SyntaxWarning
|---|---|---UnicodeWarning
|---|---|---UserWarning
|---GeneratorExit
|---KeyboardInterrupt
|---SystemExit

這也意味着在定義自己的異常時,應該將它們基於StandardError而不是Exception。

Base class for all standard Python exceptions that do not represent
interpreter exiting.

是的,你可以(對於簡單的情況),但你需要一些元編程。 與其他答案一樣,函數不會聲明它會拋出特定的錯誤類型,因此您需要查看模塊並查看它定義的異常類型或它引發的異常類型。 您可以嘗試瀏覽文檔或利用Python API執行此操作。

要首先找到模塊定義的異常類型,只需編寫一個簡單的腳本來遍歷模塊字典module.__dict__中的每個對象module.__dict__並查看它是否以單詞“Error”結尾,或者它是否是Exception的子類:

def listexns(mod):
    """Saved as: http://gist.github.com/402861
    """
    module = __import__(mod)
    exns = []
    for name in module.__dict__:
        if (issubclass(module.__dict__[name], Exception) or
            name.endswith('Error')):
            exns.append(name)
    for name in exns:
        print '%s.%s is an exception type' % (str(mod), name)
    return

如果我在你的shutils例子上運行這個我得到這個:

$ python listexn.py shutil
Looking for exception types in module: shutil
shutil.Error is an exception type
shutil.WindowsError is an exception type
$

這告訴您定義了哪些錯誤類型,但不會拋出哪些錯誤類型。 為了實現后者,我們需要遍歷Python解釋器解析模塊時生成的抽象語法樹,並查找每個raise語句,然后保存引發的名稱列表。 這個代碼有點長,所以首先我要說明輸出:

$ python listexn-raised.py /usr/lib/python2.6/shutil.py
Looking for exception types in: /usr/lib/python2.6/shutil.py
/usr/lib/python2.6/shutil.py:OSError is an exception type
/usr/lib/python2.6/shutil.py:Error is an exception type
$ 

所以,現在我們知道shutil.py定義錯誤類型ErrorWindowsError並引發異常類型OSErrorError 如果我們想要更完整,我們可以編寫另一個方法來檢查每個except子句,以查看shutil處理的異常。

這是遍歷AST的代碼,它只是使用compiler.visitor接口來創建一個walker,它實現了Gang of Four書中的“訪問者模式”:

class ExceptionFinder(visitor.ASTVisitor):
    """List all exceptions raised by a module. 
    Saved as: http://gist.github.com/402869
    """

    def __init__(self, filename):
        visitor.ASTVisitor.__init__(self)
        self.filename = filename
        self.exns = set()
        return

    def __visitName(self, node):
        """Should not be called by generic visit, otherwise every name
        will be reported as an exception type.
        """
        self.exns.add(node.name)
        return

    def __visitCallFunc(self, node):
        """Should not be called by generic visit, otherwise every name
        will be reported as an exception type.
        """
        self.__visitName(node.node)
        return

    def visitRaise(self, node):
        """Visit a raise statement.
        Cheat the default dispatcher.
        """
        if issubclass(node.expr1, compiler.ast.Name):
            self.__visitName(node.expr1)
        elif isinstance(node.expr1, compiler.ast.CallFunc):
            self.__visitCallFunc(node.expr1)
        return

由於這些操作通常使用libc函數和操作系統調用,因此大多數情況下會得到帶有錯誤號的IOError或OSError; 這些錯誤列在該libc / OS調用的手冊頁中。

我知道這可能不是一個完整的答案,最好在文檔中列出所有例外情況......

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM