Python:我怎么知道方法调用可能会抛出哪些异常
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1591319/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Python: How can I know which exceptions might be thrown from a method call
提问by GabiMe
Is there a way knowing (at coding time) which exceptions to expect when executing python code? I end up catching the base Exception class 90% of the time since I don't know which exception type might be thrown(and don't tell me to read the documentation. many times an exception can be propagated from the deep. and many times the documentation is not updated or correct). Is there some kind of tool to check this ? (like by reading the python code and libs)?
有没有办法知道(在编码时)执行 python 代码时会出现哪些异常?我最终在 90% 的情况下捕获了基本异常类,因为我不知道可能会抛出哪种异常类型(并且不要告诉我阅读文档。很多时候异常可以从深层传播。很多次文档未更新或不正确)。有什么工具可以检查这个吗?(比如通过阅读 python 代码和库)?
采纳答案by Andrey Vlasovskikh
I guess a solution could be only imprecise because of lack of static typing rules.
我想由于缺乏静态类型规则,解决方案可能只是不精确的。
I'm not aware of some tool that checks exceptions, but you could come up with your own tool matching your needs (a good chance to play a little with static analysis).
我不知道有什么工具可以检查异常,但是您可以想出符合您需求的自己的工具(这是进行静态分析的好机会)。
As a first attempt, you could write a function that builds an AST, finds all Raise
nodes, and then tries to figure out common patterns of raising exceptions (e. g. calling a constructor directly)
作为第一次尝试,您可以编写一个函数来构建 AST,查找所有Raise
节点,然后尝试找出引发异常的常见模式(例如直接调用构造函数)
Let x
be the following program:
让x
是以下程序:
x = '''\
if f(x):
raise IOError(errno.ENOENT, 'not found')
else:
e = g(x)
raise e
'''
Build the AST using the compiler
package:
使用compiler
包构建 AST :
tree = compiler.parse(x)
Then define a Raise
visitor class:
然后定义一个Raise
访问者类:
class RaiseVisitor(object):
def __init__(self):
self.nodes = []
def visitRaise(self, n):
self.nodes.append(n)
And walk the AST collecting Raise
nodes:
并遍历 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),
]
You may continue by resolving symbols using compiler symbol tables, analyzing data dependencies, etc. Or you may just deduce, that CallFunc(Name('IOError'), ...)
"should definitely mean raising IOError
", which is quite OK for quick practical results :)
您可以继续使用编译器符号表解析符号,分析数据依赖性等。或者您可以推断,CallFunc(Name('IOError'), ...)
“肯定意味着提高IOError
”,这对于快速的实际结果来说非常好:)
回答by P Shved
You should only catch exceptions that you will handle.
您应该只捕获您将处理的异常。
Catching all exceptions by their concrete types is nonsense. You should catch specific exceptions you canand willhandle. For other exceptions, you may write a generic catch that catches "base Exception", logs it (use str()
function) and terminates your program (or does something else that's appropriate in a crashy situation).
通过它们的具体类型捕获所有异常是无稽之谈。您应该捕获可以并且将处理的特定异常。对于其他异常,您可以编写一个通用的 catch 来捕获“基本异常”,记录它(使用str()
函数)并终止您的程序(或在崩溃的情况下执行其他适当的操作)。
If you really gonna handle allexceptions and are sure none of them are fatal (for example, if you're running the code in some kind of a sandboxed environment), then your approach of catching generic BaseException fits your aims.
如果您真的要处理所有异常并且确定它们都不是致命的(例如,如果您在某种沙盒环境中运行代码),那么您捕获通用 BaseException 的方法符合您的目标。
You might be also interested in language exception reference, not a reference for the library you're using.
您可能还对语言异常参考感兴趣,而不是对您正在使用的库的参考。
If the library reference is really poor and it doesn't re-throw its own exceptions when catching system ones, the only useful approach is to run tests(maybe add it to test suite, because if something is undocumented, it may change!). Delete a file crucial for your code and check what exception is being thrown. Supply too much data and check what error it yields.
如果库引用真的很差,并且在捕获系统异常时它不会重新抛出自己的异常,那么唯一有用的方法是运行测试(可能会将其添加到测试套件中,因为如果某些内容未记录,它可能会更改!) . 删除对您的代码至关重要的文件并检查正在抛出的异常。提供过多的数据并检查它产生的错误。
You will have to run tests anyway, since, even if the method of getting the exceptions by source code existed, it wouldn't give you any idea how you should handle any of those. Maybe you should be showing error message "File needful.txt is not found!" when you catch IndexError
? Only test can tell.
无论如何您都必须运行测试,因为即使存在通过源代码获取异常的方法,它也不会让您知道应该如何处理其中的任何一个。也许您应该显示错误消息“找不到文件 needful.txt!” 你IndexError
什么时候抓到?只有测试才能知道。
回答by John La Rooy
The correct tool to solve this problem is unittests. If you are having exceptions raised by real code that the unittests do not raise, then you need more unittests.
解决这个问题的正确工具是单元测试。如果您遇到由单元测试未引发的真实代码引发的异常,那么您需要更多单元测试。
Consider this
考虑这个
def f(duck):
try:
duck.quack()
except ??? could be anything
duck can be any object
鸭子可以是任何对象
Obviously you can have an AttributeError
if duck has no quack, a TypeError
if duck has a quack but it is not callable. You have no idea what duck.quack()
might raise though, maybe even a DuckError
or something
显然你可以有一个AttributeError
if 鸭子没有嘎嘎声,一个TypeError
if 鸭子有一个嘎嘎声但它是不可调用的。你不知道duck.quack()
可能会增加什么,甚至可能是DuckError
什么
Now supposing you have code like this
现在假设你有这样的代码
arr[i] = get_something_from_database()
If it raises an IndexError
you don't know whether it has come from arr[i] or from deep inside the database function. usually it doesn't matter so much where the exception occurred, rather that something went wrong and what you wanted to happen didn't happen.
如果它引发 anIndexError
你不知道它是来自 arr[i] 还是来自数据库函数的深处。通常,异常发生的位置并不重要,而是出现问题并且您想要发生的事情没有发生。
A handy technique is to catch and maybe reraise the exception like this
一个方便的技术是捕获并可能重新引发这样的异常
except Exception as e
#inspect e, decide what to do
raise
回答by viraptor
Noone explained so far, why you can't have a full, 100% correct list of exceptions, so I thought it's worth commenting on. One of the reasons is a first-class function. Let's say that you have a function like this:
到目前为止没有人解释过,为什么你不能有一个完整的,100% 正确的异常列表,所以我认为值得评论。原因之一是一流的功能。假设你有一个这样的函数:
def apl(f,arg):
return f(arg)
Now apl
can raise any exception that f
raises. While there are not many functions like that in the core library, anything that uses list comprehension with custom filters, map, reduce, etc. are affected.
现在apl
可以引发任何f
引发的异常。虽然核心库中没有很多类似的功能,但任何使用列表理解和自定义过滤器、映射、减少等的功能都会受到影响。
The documentation and the source analysers are the only "serious" sources of information here. Just keep in mind what they cannot do.
文档和源分析器是这里唯一的“严肃”信息来源。只要记住他们不能做什么。
回答by Kurt
I ran into this when using socket, I wanted to find out all the error conditions I would run in to (so rather than trying to create errors and figure out what socket does I just wanted a concise list). Ultimately I ended up grep'ing "/usr/lib64/python2.4/test/test_socket.py" for "raise":
我在使用 socket 时遇到了这个问题,我想找出我会遇到的所有错误情况(因此,与其试图创建错误并找出是什么 socket,我只想要一个简明的列表)。最终,我最终将“/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,
Which is a pretty concise list of errors. Now of course this only works on a case by case basis and depends on the tests being accurate (which they usually are). Otherwise you need to pretty much catch all exceptions, log them and dissect them and figure out how to handle them (which with unit testing wouldn't be to difficult).
这是一个非常简洁的错误列表。当然,这仅适用于个案,并取决于测试是否准确(通常是这样)。否则,您几乎需要捕获所有异常,记录它们并剖析它们并弄清楚如何处理它们(通过单元测试不会很难)。
回答by SilentGhost
normally, you'd need to catch exception only around a few lines of code. You wouldn't want to put your whole main
function into the try except
clause. for every few line you always should now (or be able easily to check) what kind of exception might be raised.
通常,您只需要在几行代码附近捕获异常。您不想将整个main
函数放入try except
子句中。对于每几行,您现在应该(或能够轻松检查)可能引发什么样的异常。
docs have an exhaustive list of built-in exceptions. don't try to except those exception that you're not expecting, they might be handled/expected in the calling code.
文档有一个详尽的内置异常列表。不要试图排除那些您不期望的异常,它们可能会在调用代码中被处理/预期。
edit: what might be thrown depends on obviously on what you're doing! accessing random element of a sequence: IndexError
, random element of a dict: KeyError
, etc.
编辑:可能抛出什么显然取决于你在做什么!访问序列的IndexError
随机元素:KeyError
,字典的随机元素:等。
Just try to run those few lines in IDLE and cause an exception. But unittest would be a better solution, naturally.
只需尝试在 IDLE 中运行这几行并导致异常。但单元测试自然是一个更好的解决方案。
回答by Rahav
There are two ways that I found informative. The first one, run the instructions in iPython, which will display the exception type.
我发现有两种方法可以提供信息。第一个,在 iPython 中运行指令,它将显示异常类型。
n = 2
str = 'me '
str + 2
TypeError: unsupported operand type(s) for +: 'int' and 'str'
In the second way we settle for catching too much and improving on it. Include a try expression in your code and catch except Exception as err. Print sufficient data to know what exception was thrown. As exceptions are thrown improve your code by adding a more precise except clause. When you feel that you have cached all relevant exceptions remove the all inclusive one. A good thing to do anyway because it swallows programming errors.
在第二种方式中,我们满足于捕捉太多并改进它。在您的代码中包含一个 try 表达式并捕获除了 Exception 作为 err。打印足够的数据以了解抛出了什么异常。在抛出异常时,通过添加更精确的 except 子句来改进您的代码。当你觉得你已经缓存了所有相关的异常时,删除所有包含的异常。无论如何都是一件好事,因为它可以解决编程错误。
try:
so something
except Exception as err:
print "Some message"
print err.__class__
print err
exit(1)