[英]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
定義錯誤類型Error
和WindowsError
並引發異常類型OSError
和Error
。 如果我們想要更完整,我們可以編寫另一個方法來檢查每個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.