有没有一种方法(在编码时)知道在执行python代码时期望哪些异常?由于我不知道可能抛出哪种异常类型(并且不要告诉我阅读文档,所以很多时候我都会捕获90%的基类Exception。很多时候,可以从深处传播异常。)次文档未更新或不正确)。有某种工具可以检查吗?(例如通过阅读python代码和库)?
except Exception
在Python 2.6及更高版本中捕获字符串异常的效果很好。
有没有一种方法(在编码时)知道在执行python代码时期望哪些异常?由于我不知道可能抛出哪种异常类型(并且不要告诉我阅读文档,所以很多时候我都会捕获90%的基类Exception。很多时候,可以从深处传播异常。)次文档未更新或不正确)。有某种工具可以检查吗?(例如通过阅读python代码和库)?
except Exception
在Python 2.6及更高版本中捕获字符串异常的效果很好。
Answers:
我猜一个解决方案可能只是不精确,因为缺少静态的输入规则。
我不知道有一些检查异常的工具,但是您可以根据自己的需求提出自己的工具(这是一个很好的机会来进行静态分析)。
第一次尝试,您可以编写一个构建AST的函数,查找所有Raise
节点,然后尝试找出引发异常的常见模式(例如,直接调用构造函数)
让x
下面的程序为例:
x = '''\
if f(x):
raise IOError(errno.ENOENT, 'not found')
else:
e = g(x)
raise e
'''
使用compiler
包构建AST :
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),
]
您可以继续使用编译器符号表解析符号,分析数据依赖关系等。或者您可以推断出CallFunc(Name('IOError'), ...)
“绝对应该意味着加注IOError
”,对于快速实用的结果来说是可以的:)
v.nodes
上面的值,您实际上不能说什么是Name('IOError')
或Name('e')
。你不知道什么样的价值(S)的IOError
和e
可以指向,因为他们是所谓的自由变量。即使知道它们的绑定上下文(在这里符号表起作用),您也应该执行某种数据依赖关系分析以推断出它们的确切值(这在Python中应该很难做到)。
['IOError(errno.ENOENT, "not found")', 'e']
向用户显示的列表就可以了。但是您不能推断出由字符串表示的变量的值的实际类别:)(很抱歉重新发布)
exc_class = raw_input(); exec "raise " + exc_class
。关键是,在像Python这样的动态语言中,这种静态分析是不可能实现的。
find /path/to/library -name '*.py' | grep 'raise '
得到类似的结果:)
您应该只捕获将要处理的异常。
按照具体类型捕获所有异常是胡说八道。您应该捕获可以并且将要处理的特定异常。对于其他异常,您可以编写一个通用捕获来捕获“基本异常”,将其记录(使用str()
函数)并终止程序(或执行其他在崩溃情况下适当的操作)。
如果您真的要处理所有异常,并确保它们都不是致命的(例如,如果您在某种沙盒环境中运行代码),那么捕获通用BaseException的方法就可以满足您的目标。
您可能还对语言异常参考感兴趣,而不是所用库的参考。
如果库引用确实很差,并且在捕获系统异常时没有重新抛出其自身的异常,则唯一有用的方法是运行测试(可能将其添加到测试套件中,因为如果未记录某些内容,则可能会更改!) 。删除对您的代码至关重要的文件,然后检查抛出了什么异常。提供过多的数据,并检查其产生什么错误。
无论如何,您都将必须运行测试,因为即使存在通过源代码获取异常的方法,也不会让您知道如何处理这些异常。也许您应该显示错误消息“找不到文件needful.txt!” 什么时候抓到IndexError
?只有测试可以证明。
解决此问题的正确工具是单元测试。如果您在真实代码中引发了单元测试不会引发的异常,那么您需要更多的单元测试。
考虑一下
def f(duck):
try:
duck.quack()
except ??? could be anything
鸭子可以是任何物体
显然,您可以拥有一个AttributeError
if鸭没有嘎嘎声,一个TypeError
if鸭有嘎嘎声,但是它不能被召唤。您不知道duck.quack()
可能会发生什么,甚至可能是DuckError
什么
现在假设您有这样的代码
arr[i] = get_something_from_database()
如果它引发a IndexError
,则不知道它是来自arr [i]还是来自数据库函数内部。通常,异常发生的位置并不重要,而出了什么问题以及您想发生的事情却没有发生。
一个方便的技术是捕获并提出这样的异常
except Exception as e
#inspect e, decide what to do
raise
我在使用套接字时遇到了这个问题,我想找出我将要遇到的所有错误情况(因此,与其尝试创建错误并弄清楚我只想要一个简洁的列表,不如尝试创建错误)。最终,我最终将“ /usr/lib64/python2.4/test/test_socket.py”替换为“ raise”:
$ 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,
这是一个非常简洁的错误列表。当然,现在这仅取决于具体情况,并且取决于测试的准确性(通常是正确的)。否则,您几乎需要捕获所有异常,将其记录下来并进行剖析,并弄清楚如何处理它们(使用单元测试就不那么困难了)。
我发现有两种方法可以提供信息。第一个,在iPython中运行代码,它将显示异常类型。
n = 2
str = 'me '
str + 2
TypeError: unsupported operand type(s) for +: 'int' and 'str'
第二种方法是我们适应于捕获过多的漏洞,并随着时间的推移不断改进。try
在您的代码中包含一个表达式并catch except Exception as err
。打印足够的数据以了解引发了什么异常。当抛出异常时,通过添加更精确的except
子句来改进代码。当您感觉已捕获所有相关异常时,请删除所有包含的异常。无论如何都是一件好事,因为它会吞噬编程错误。
try:
so something
except Exception as err:
print "Some message"
print err.__class__
print err
exit(1)
通常,您只需捕获几行代码即可捕获异常。您不想将整个main
函数放到该try except
子句中。对于每行几行,您现在始终应该(或能够轻松检查)可能引发的异常类型。
docs有详尽的内置异常列表。不要尝试除您不期望的那些异常之外,它们可能在调用代码中得到处理/预期。
编辑:可能会抛出什么显然取决于您在做什么!访问sequence:的IndexError
随机元素,dict:的随机元素KeyError
,等等。
只需尝试在IDLE中运行这几行并引起异常。但是,单元测试自然是一个更好的解决方案。
raise
字符串,而不仅仅是BaseException
子类。因此,如果您要调用的代码超出了您的控制范围,那甚至except Exception
是不够的,因为它不会捕获字符串异常。正如其他人指出的那样,您在这里树错了树。