Python:我怎么知道哪些exception可能会从方法调用中抛出

有没有一种方法知道(在编码时)执行python代码期望的exception? 由于我不知道可能引发哪种exceptiontypes,所以我最终在90%的时间内捕获了基类exception类(并且不要告诉我阅读文档,很多时候exception可以从深处传播出来,次文档不更新或正确)。 有没有某种工具来检查这个? (如通过阅读Python代码和库)?

我想一个解决scheme可能只是因为缺乏静态的input规则而不精确。

我不知道有一些工具可以检查exception,但是你可以拿出自己的工具来满足你的需求(这是一个很好的机会,可以用静态分析)。

作为第一次尝试,您可以编写一个函数来构buildAST,find所有Raise节点,然后尝试找出引发exception的常见模式(例如直接调用构造函数)

x是以下程序:

 x = '''\ if f(x): raise IOError(errno.ENOENT, 'not found') else: e = g(x) raise e ''' 

使用compiler包构buildAST:

 tree = compiler.parse(x) 

然后定义一个Raise访问者类:

 class RaiseVisitor(object): def __init__(self): self.nodes = [] def visitRaise(self, n): self.nodes.append(n) 

然后走AST收集Raise节点:

 v = RaiseVisitor() compiler.walk(tree, v) >>> print v.nodes [ Raise( CallFunc( Name('IOError'), [Getattr(Name('errno'), 'ENOENT'), Const('not found')], None, None), None, None), Raise(Name('e'), None, None), ] 

你可以继续使用编译器符号表来parsing符号,分析数据的依赖关系等。或者你可以推断出, CallFunc(Name('IOError'), ...) “肯定意味着提高IOError ”,这对于快速的实际效果:)

你应该只捕捉你将要处理的exception。

通过具体的types捕获所有的exception是无稽之谈。 你应该抓住特定的例外,你可以 并将处理。 对于其他的例外情况,你可以编写一个捕获“基本exception”的通用catch,logging它(使用str()函数)并终止你的程序(或者在崩溃的情况下做其他适当的事情)。

如果你真的要处理所有的exception,并确定没有一个是致命的(例如,如果你在某种沙箱环境下运行代码),那么捕获genericsBaseException的方法就符合你的目的。

您可能也对语言exception引用感兴趣,而不是您正在使用的库的参考。

如果库引用真的很差,并且在捕获系统exception时不重新抛出它自己的exception, 唯一有用的方法是运行testing (也许将其添加到testing套件中,因为如果某些东西没有logging,它可能会改变!) 。 删除对您的代码至关重要的文件,并检查正在抛出什么exception。 提供太多的数据并检查产生的错误。

无论如何,你将不得不运行testing,因为即使通过源代码获取exception的方法存在,也不会告诉你如何处理这些exception 。 也许你应该显示错误信息“File needful.txt is not found!” 当你抓到IndexError ? 只有testing可以告诉。

解决这个问题的正确工具是unittests。 如果你有真正的代码提出exception,单位testing不提高,那么你需要更多的单位testing。

考虑一下

 def f(duck): try: duck.quack() except ??? could be anything 

鸭子可以是任何物体

如果鸭子没有嘎嘎,显然你可以有一个AttributeError ,如果鸭子有一个嘎嘎,但是它是不可调用的。 你不知道duck.quack()可能会引发什么,甚至可能是一个DuckError或什么的

现在假设你有这样的代码

 arr[i] = get_something_from_database() 

如果它引发了IndexError你不知道它是来自arr [i]还是来自数据库函数内部。 通常情况下,发生exception的地方并不重要,而是出现了一些问题,而您想要发生的事情也没有发生。

一个方便的技术是捕捉,也许重新这样的例外

 except Exception as e #inspect e, decide what to do raise 

我在使用套接字时遇到了这个问题,我想找出所有的错误条件(我不想试图创build错误并找出我想要的简洁列表)。 最后,我最终为“raise”grep'ing“/usr/lib64/python2.4/test/test_socket.py”:

 $ grep raise test_socket.py Any exceptions raised by the clients during their tests raise TypeError, "test_func must be a callable function" raise NotImplementedError, "clientSetUp must be implemented." def raise_error(*args, **kwargs): raise socket.error def raise_herror(*args, **kwargs): raise socket.herror def raise_gaierror(*args, **kwargs): raise socket.gaierror self.failUnlessRaises(socket.error, raise_error, self.failUnlessRaises(socket.error, raise_herror, self.failUnlessRaises(socket.error, raise_gaierror, raise socket.error # Check that setting it to an invalid value raises ValueError # Check that setting it to an invalid type raises TypeError def raise_timeout(*args, **kwargs): self.failUnlessRaises(socket.timeout, raise_timeout, def raise_timeout(*args, **kwargs): self.failUnlessRaises(socket.timeout, raise_timeout, 

这是一个非常简洁的错误列表。 现在当然这只适用于个案,取决于testing的准确性(通常是这些testing)。 否则,你需要几乎捕捉所有的exception,logging下来并parsing它们,弄清楚如何处理它们(unit testing不会太难)。

目前还没有人解释,为什么你不能有一个完整的100%正确的例外列表,所以我认为这是值得评论。 其中一个原因就是一stream的function。 假设你有这样的function:

 def apl(f,arg): return f(arg) 

现在apl可以引发任何exception。 虽然在核心库中没有太多function,但是使用自定义filter,map,reduce等的列表理解的任何东西都会受到影响。

文档和源代码分析器是这里唯一“严重”的信息来源。 只要记住他们不能做的事情。

通常情况下,您只需要在几行代码中捕获exception。 你不希望把你的整个main函数放到try except语句中。 对于你现在总是应该每隔几行(或能够容易地检查)可能引发什么样的exception。

docs有一个内置的例外的详尽清单 。 不要试图去除那些你不期望的exception,它们可能会在调用代码中被处理/预期。

编辑 :什么可能会被抛出显然取决于你在做什么! 访问序列的随机元素: IndexError ,字典的随机元素: KeyError

只要尝试在IDLE中运行这些行,并导致exception。 但unit testing自然会是一个更好的解决scheme。

有两种方法,我发现信息。 第一个,运行iPython中的指令,它将显示exceptiontypes。

 n = 2 str = 'me ' str + 2 TypeError: unsupported operand type(s) for +: 'int' and 'str' 

在第二种方式,我们解决了捕捉太多,并改善它。 在你的代码中包含一个try语句, 除了Exception之外 ,还可以捕获它。 打印足够的数据以知道抛出了什么exception。 抛出exception通过添加更精确的except子句来改善您的代码。 如果您觉得已经caching了所有相关的exception,请删除全部包含的exception。 无论如何,这是件好事,因为它吞噬了编程错误。

 try: so something except Exception as err: print "Some message" print err.__class__ print err exit(1)