对于长标题感到抱歉,但对我的问题似乎最具描述性。
基本上,我很难在官方python文档中找到异常信息。例如,在我正在编写的一个程序中,我正在使用shutil libary的移动函数:
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.'
任何可以将我链接到我在某些官方文档中忽略的相关文档,或者提供一种确定的方法来确定哪些函数抛出哪些异常以及原因。 / p>
谢谢!
更新:从给出的答案看来,似乎没有100%直接的方法来确定特定功能引发的错误。使用元编程,似乎我可以找出简单的情况并列出一些例外,但这不是一个特别有用或方便的方法。
我想最终会有一些标准来定义每个python函数引发的异常,并且这些信息将包含在官方文档中。在那之前,我想我会允许这些异常通过并为我的用户输出错误,因为它似乎是最理智的事情。
答案 0 :(得分:12)
为了放大Messa,抓住你所期望的失败模式,你知道如何恢复。 Ian Bicking写了an article,它解决了一些总体原则,就像Eli Bendersky的note一样。
示例代码的问题在于不处理错误,只是美化它们并丢弃它们。你的代码并不“知道”如何处理NameError,除了传递它之外没有什么应该做的,如果你认为必须添加细节,请查看Bicking的重新加注。
对于shutil.move
,IOError和OSError是合理的“可预期的”,但不一定可以处理。你的函数的调用者希望它移动一个文件,如果Eli写的“契约”被破坏,它本身可能会破坏。
抓住你可以修复,装饰和重新提升你期望但无法解决的东西,并让调用者处理你没想到的东西,即使“处理”的代码是堆栈的七个级别在main
。
答案 1 :(得分:4)
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而不是异常。
Base class for all standard Python exceptions that do not represent
interpreter exiting.
答案 2 :(得分:3)
是的,您可以(对于简单的情况),但您需要一些元编程。与其他答案一样,函数不会声明它会抛出特定的错误类型,因此您需要查看模块并查看它定义的异常类型或它引发的异常类型。您可以尝试浏览文档或利用Python API执行此操作。
要首先找到模块定义的异常类型,只需编写一个简单的脚本来遍历模块字典module.__dict__
中的每个对象,看它是否以单词“Error”结尾,或者它是否为子类的子类例外:
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
答案 3 :(得分:2)
由于这些操作通常使用libc函数和操作系统调用,因此大多数情况下会得到带有 errno 编号的IOError或OSError;这些错误列在该libc / OS调用的手册页中。
我知道这可能不是一个完整的答案,最好在文档中列出所有例外......