标签归档:exception-handling

如何在不停止程序的情况下打印完整的回溯?

问题:如何在不停止程序的情况下打印完整的回溯?

我正在编写一个程序,该程序可以解析10个网站,找到数据文件,保存文件,然后解析它们以生成可以在NumPy库中轻松使用的数据。有万吨通过不良链接,不好的XML,缺项,其他的事情我还没有进行分类文件遇到错误的。我最初制作该程序来处理以下错误:

try:
    do_stuff()
except:
    pass

但是现在我想记录错误:

try:
    do_stuff()
except Exception, err:
    print Exception, err

请注意,这是打印到日志文件中以供以后查看。这通常会打印非常无用的数据。我想要的是在错误触发时打印完全相同的行,而没有try-except拦截异常,但是我不希望它暂停我的程序,因为它嵌套在我想要的一系列for循环中看到完成。

I’m writing a program that parses 10 websites, locates data files, saves the files, and then parses them to make data that can be readily used in the NumPy library. There are tons of errors this file encounters through bad links, poorly formed XML, missing entries, and other things I’ve yet to categorize. I initially made this program to handle errors like this:

try:
    do_stuff()
except:
    pass

But now I want to log errors:

try:
    do_stuff()
except Exception, err:
    print Exception, err

Note this is printing to a log file for later review. This usually prints very useless data. What I want is to print the exact same lines printed when the error triggers without the try-except intercepting the exception, but I don’t want it to halt my program since it is nested in a series of for loops that I would like to see to completion.


回答 0

其他一些答案已经指出了追溯模块。

请注意,使用print_exc,在某些特殊情况下,您将无法获得预期的结果。在Python 2.x中:

import traceback

try:
    raise TypeError("Oups!")
except Exception, err:
    try:
        raise TypeError("Again !?!")
    except:
        pass

    traceback.print_exc()

…将显示最后一个异常的回溯:

Traceback (most recent call last):
  File "e.py", line 7, in <module>
    raise TypeError("Again !?!")
TypeError: Again !?!

如果您确实需要访问原始的追溯,一种解决方案是将异常信息exc_info本地变量中返回,并使用来显示它print_exception

import traceback
import sys

try:
    raise TypeError("Oups!")
except Exception, err:
    try:
        exc_info = sys.exc_info()

        # do you usefull stuff here
        # (potentially raising an exception)
        try:
            raise TypeError("Again !?!")
        except:
            pass
        # end of useful stuff


    finally:
        # Display the *original* exception
        traceback.print_exception(*exc_info)
        del exc_info

生产:

Traceback (most recent call last):
  File "t.py", line 6, in <module>
    raise TypeError("Oups!")
TypeError: Oups!

很少有这个陷阱:

  • 从文档sys_info

    在处理异常的函数中将回溯返回值分配给局部变量将导致循环引用。这将防止垃圾回收由同一函数中的局部变量或回溯引用的任何内容。[…] 如果确实需要回溯,请确保在使用后将其删除(最好通过try … finally语句完成)

  • 但是,根据同一文档:

    从Python 2.2开始,启用垃圾收集并使其无法访问时,会自动回收此类循环,但是避免创建循环仍然更加有效。


另一方面,通过允许您访问异常关联的回溯,Python 3产生了一个不太令人惊讶的结果:

import traceback

try:
    raise TypeError("Oups!")
except Exception as err:
    try:
        raise TypeError("Again !?!")
    except:
        pass

    traceback.print_tb(err.__traceback__)

…将显示:

  File "e3.py", line 4, in <module>
    raise TypeError("Oups!")

Some other answer have already pointed out the traceback module.

Please notice that with print_exc, in some corner cases, you will not obtain what you would expect. In Python 2.x:

import traceback

try:
    raise TypeError("Oups!")
except Exception, err:
    try:
        raise TypeError("Again !?!")
    except:
        pass

    traceback.print_exc()

…will display the traceback of the last exception:

Traceback (most recent call last):
  File "e.py", line 7, in <module>
    raise TypeError("Again !?!")
TypeError: Again !?!

If you really need to access the original traceback one solution is to cache the exception infos as returned from exc_info in a local variable and display it using print_exception:

import traceback
import sys

try:
    raise TypeError("Oups!")
except Exception, err:
    try:
        exc_info = sys.exc_info()

        # do you usefull stuff here
        # (potentially raising an exception)
        try:
            raise TypeError("Again !?!")
        except:
            pass
        # end of useful stuff


    finally:
        # Display the *original* exception
        traceback.print_exception(*exc_info)
        del exc_info

Producing:

Traceback (most recent call last):
  File "t.py", line 6, in <module>
    raise TypeError("Oups!")
TypeError: Oups!

Few pitfalls with this though:

  • From the doc of sys_info:

    Assigning the traceback return value to a local variable in a function that is handling an exception will cause a circular reference. This will prevent anything referenced by a local variable in the same function or by the traceback from being garbage collected. […] If you do need the traceback, make sure to delete it after use (best done with a try … finally statement)

  • but, from the same doc:

    Beginning with Python 2.2, such cycles are automatically reclaimed when garbage collection is enabled and they become unreachable, but it remains more efficient to avoid creating cycles.


On the other hand, by allowing you to access the traceback associated with an exception, Python 3 produce a less surprising result:

import traceback

try:
    raise TypeError("Oups!")
except Exception as err:
    try:
        raise TypeError("Again !?!")
    except:
        pass

    traceback.print_tb(err.__traceback__)

… will display:

  File "e3.py", line 4, in <module>
    raise TypeError("Oups!")

回答 1

traceback.format_exc()sys.exc_info()会产生更多信息(如果您想要的话)。

import traceback
import sys

try:
    do_stuff()
except Exception:
    print(traceback.format_exc())
    # or
    print(sys.exc_info()[2])

traceback.format_exc() or sys.exc_info() will yield more info if that’s what you want.

import traceback
import sys

try:
    do_stuff()
except Exception:
    print(traceback.format_exc())
    # or
    print(sys.exc_info()[2])

回答 2

如果您正在调试,并且只想查看当前的堆栈跟踪,则可以简单地调用:

traceback.print_stack()

无需为了再次捕获而手动引发异常。

If you’re debugging and just want to see the current stack trace, you can simply call:

traceback.print_stack()

There’s no need to manually raise an exception just to catch it again.


回答 3

如何在不停止程序的情况下打印完整的回溯?

当您不想因错误而暂停程序时,需要使用try / except处理该错误:

try:
    do_something_that_might_error()
except Exception as error:
    handle_the_error(error)

要提取完整的追溯,我们将使用traceback标准库中的模块:

import traceback

并创建一个相当复杂的堆栈跟踪以演示我们获得了完整的堆栈跟踪:

def raise_error():
    raise RuntimeError('something bad happened!')

def do_something_that_might_error():
    raise_error()

列印

打印完整的回溯,请使用以下traceback.print_exc方法:

try:
    do_something_that_might_error()
except Exception as error:
    traceback.print_exc()

哪些打印:

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

比打印,记录更好:

但是,最佳实践是为模块设置一个记录器。它将知道模块的名称,并能够更改级别(在其他属性中,例如处理程序)

import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

在这种情况下,您将需要该logger.exception函数:

try:
    do_something_that_might_error()
except Exception as error:
    logger.exception(error)

哪个日志:

ERROR:__main__:something bad happened!
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

或者,也许您只想要字符串,在这种情况下,您将需要traceback.format_exc函数:

try:
    do_something_that_might_error()
except Exception as error:
    logger.debug(traceback.format_exc())

哪个日志:

DEBUG:__main__:Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

结论

对于这三个选项,我们看到的输出与发生错误时的输出相同:

>>> do_something_that_might_error()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

How to print the full traceback without halting the program?

When you don’t want to halt your program on an error, you need to handle that error with a try/except:

try:
    do_something_that_might_error()
except Exception as error:
    handle_the_error(error)

To extract the full traceback, we’ll use the traceback module from the standard library:

import traceback

And to create a decently complicated stacktrace to demonstrate that we get the full stacktrace:

def raise_error():
    raise RuntimeError('something bad happened!')

def do_something_that_might_error():
    raise_error()

Printing

To print the full traceback, use the traceback.print_exc method:

try:
    do_something_that_might_error()
except Exception as error:
    traceback.print_exc()

Which prints:

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

Better than printing, logging:

However, a best practice is to have a logger set up for your module. It will know the name of the module and be able to change levels (among other attributes, such as handlers)

import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

In which case, you’ll want the logger.exception function instead:

try:
    do_something_that_might_error()
except Exception as error:
    logger.exception(error)

Which logs:

ERROR:__main__:something bad happened!
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

Or perhaps you just want the string, in which case, you’ll want the traceback.format_exc function instead:

try:
    do_something_that_might_error()
except Exception as error:
    logger.debug(traceback.format_exc())

Which logs:

DEBUG:__main__:Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

Conclusion

And for all three options, we see we get the same output as when we have an error:

>>> do_something_that_might_error()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

回答 4

首先,不要用printS表示日志记录,有非稳态,证明和深思熟虑的STDLIB模块,这样做:logging。您绝对应该使用它。

其次,当存在本机且简单的方法时,不要试图将无关的工具弄得一团糟。这里是:

log = logging.getLogger(__name__)

try:
    call_code_that_fails()
except MyError:
    log.exception('Any extra info you want to see in your logs')

而已。现在完成了。

对任何对引擎盖如何工作感兴趣的人的解释

什么log.exception是真正做只是为了通话log.error(即记录与级别的事件ERROR,并打印回溯然后。

为什么会更好?

好,这是一些注意事项:

  • 这是正确的 ;
  • 这很简单;
  • 很简单。

为什么没有人可以使用traceback记录仪exc_info=True或与其通话,或者弄脏记录仪sys.exc_info

好吧,只是因为!它们全都出于不同的目的而存在。例如,traceback.print_exc的输出与解释器本身产生的回溯有些不同。如果您使用它,则会使任何人阅读您的日志感到困惑,他们会撞到他们的头。

传递exc_info=True日志记录是不合适的。但是,当捕获可恢复的错误并且您还希望使用INFO回溯记录它们(使用例如级别)时,它很有用,因为它log.exception只会生成一个级别的日志- ERROR

而且,您绝对应该尽可能避免混乱sys.exc_info。它不是一个公共接口,而是一个内部接口- 如果您完全知道自己在做什么,就可以使用它。它不仅仅用于打印exceptions。

First, don’t use prints for logging, there is astable, proven and well-thought out stdlib module to do that: logging. You definitely should use it instead.

Second, don’t be tempted to do a mess with unrelated tools when there is native and simple approach. Here it is:

log = logging.getLogger(__name__)

try:
    call_code_that_fails()
except MyError:
    log.exception('Any extra info you want to see in your logs')

That’s it. You are done now.

Explanation for anyone who is interested in how things work under the hood

What log.exception is actually doing is just a call to log.error (that is, log event with level ERROR) and print traceback then.

Why is it better?

Well, here is some considerations:

  • it is just right;
  • it is straightforward;
  • it is simple.

Why should nobody use traceback or call logger with exc_info=True or get their hands dirty with sys.exc_info?

Well, just because! They all exist for different purposes. For example, traceback.print_exc‘s output is a little bit different from tracebacks produced by the interpreter itself. If you use it, you will confuse anyone who reads your logs, they will be banging their heads against them.

Passing exc_info=True to log calls is just inappropriate. But, it is useful when catching recoverable errors and you want to log them (using, e.g INFO level) with tracebacks as well, because log.exception produces logs of only one level – ERROR.

And you definitely should avoid messing with sys.exc_info as much as you can. It’s just not a public interface, it’s an internal one – you can use it if you definitely know what you are doing. It is not intended for just printing exceptions.


回答 5

除了@Aaron Hall的答案外,如果您正在记录日志,但又不想使用logging.exception()(由于它记录为ERROR级别),则可以使用较低级别并通过exc_info=True。例如

try:
    do_something_that_might_error()
except Exception:
    logger.info('General exception noted.', exc_info=True)

In addition to @Aaron Hall’s answer, if you are logging, but don’t want to use logging.exception() (since it logs at the ERROR level), you can use a lower level and pass exc_info=True. e.g.

try:
    do_something_that_might_error()
except Exception:
    logger.info('General exception noted.', exc_info=True)

回答 6

为了得到精确的堆栈跟踪,作为一个字符串,已如果没有尝试/除非在那里步过它,只是把这个在除块捕获违规的异常上升。

desired_trace = traceback.format_exc(sys.exc_info())

这是使用方法(假设flaky_func已定义,并log调用了您喜欢的日志系统):

import traceback
import sys

try:
    flaky_func()
except KeyboardInterrupt:
    raise
except Exception:
    desired_trace = traceback.format_exc(sys.exc_info())
    log(desired_trace)

捕获并重新引发KeyboardInterrupts 是一个好主意,这样您仍然可以使用Ctrl-C终止程序。日志记录不在问题范围之内,但是不错的选择是loggingsystraceback模块的文档。

To get the precise stack trace, as a string, that would have been raised if no try/except were there to step over it, simply place this in the except block that catches the offending exception.

desired_trace = traceback.format_exc(sys.exc_info())

Here’s how to use it (assuming flaky_func is defined, and log calls your favorite logging system):

import traceback
import sys

try:
    flaky_func()
except KeyboardInterrupt:
    raise
except Exception:
    desired_trace = traceback.format_exc(sys.exc_info())
    log(desired_trace)

It’s a good idea to catch and re-raise KeyboardInterrupts, so that you can still kill the program using Ctrl-C. Logging is outside the scope of the question, but a good option is logging. Documentation for the sys and traceback modules.


回答 7

您需要将try / except放到可能发生错误的最内部循环中,即

for i in something:
    for j in somethingelse:
        for k in whatever:
            try:
                something_complex(i, j, k)
            except Exception, e:
                print e
        try:
            something_less_complex(i, j)
        except Exception, e:
            print e

… 等等

换句话说,您需要将可能在try / except中失败的语句包装在尽可能多的内部循环中,并尽可能不具体。

You will need to put the try/except inside the most innerloop where the error may occur, i.e.

for i in something:
    for j in somethingelse:
        for k in whatever:
            try:
                something_complex(i, j, k)
            except Exception, e:
                print e
        try:
            something_less_complex(i, j)
        except Exception, e:
            print e

… and so on

In other words, you will need to wrap statements that may fail in try/except as specific as possible, in the most inner-loop as possible.


回答 8

关于此答案的评论:print(traceback.format_exc())对我来说,做得更好traceback.print_exc()。对于后者,hello有时会奇怪地将其与回溯文本“混合”,例如,如果两者都想同时写入stdout或stderr,则会产生奇怪的输出(至少在文本编辑器内部进行构建并在“构建结果”面板)。

追溯(最近一次通话):
文件“ C:\ Users \ User \ Desktop \ test.py”,第7行,在
地狱 do_stuff()
文件“ C:\ Users \ User \ Desktop \ test.py”,第4行,在do_stuff
1/0
ZeroDivisionError中:整数除或以零为模的
o
[在0.1s内完成]

所以我用:

import traceback, sys

def do_stuff():
    1/0

try:
    do_stuff()
except Exception:
    print(traceback.format_exc())
    print('hello')

A remark about this answer‘s comments: print(traceback.format_exc()) does a better job for me than traceback.print_exc(). With the latter, the hello is sometimes strangely “mixed” with the traceback text, like if both want to write to stdout or stderr at the same time, producing weird output (at least when building from inside a text editor and viewing the output in the “Build results” panel).

Traceback (most recent call last):
File “C:\Users\User\Desktop\test.py”, line 7, in
hell do_stuff()
File “C:\Users\User\Desktop\test.py”, line 4, in do_stuff
1/0
ZeroDivisionError: integer division or modulo by zero
o
[Finished in 0.1s]

So I use:

import traceback, sys

def do_stuff():
    1/0

try:
    do_stuff()
except Exception:
    print(traceback.format_exc())
    print('hello')

回答 9

我在其他任何答案中都没有提到这一点。如果出于某种原因要传递Exception对象…

在Python 3.5+中,您可以使用traceback.TracebackException.from_exception()从Exception对象获取跟踪。例如:

import traceback


def stack_lvl_3():
    raise Exception('a1', 'b2', 'c3')


def stack_lvl_2():
    try:
        stack_lvl_3()
    except Exception as e:
        # raise
        return e


def stack_lvl_1():
    e = stack_lvl_2()
    return e

e = stack_lvl_1()

tb1 = traceback.TracebackException.from_exception(e)
print(''.join(tb1.format()))

但是,以上代码导致:

Traceback (most recent call last):
  File "exc.py", line 10, in stack_lvl_2
    stack_lvl_3()
  File "exc.py", line 5, in stack_lvl_3
    raise Exception('a1', 'b2', 'c3')
Exception: ('a1', 'b2', 'c3')

这只是堆栈的两个级别,与在引发异常stack_lvl_2()但未拦截异常的情况下在屏幕上显示的内容相反(取消注释# raise行)。

据我了解,这是因为stack_lvl_3()在这种情况下,异常在引发时仅记录堆栈的当前级别。随着它在堆栈中的传递,它被添加了更多的层次__traceback__。但是我们在中截获了它stack_lvl_2(),这意味着它要记录的只是3级和2级。要获得在stdout上打印的完整轨迹,我们必须在最高(最低?)级捕获它:

import traceback


def stack_lvl_3():
    raise Exception('a1', 'b2', 'c3')


def stack_lvl_2():
    stack_lvl_3()


def stack_lvl_1():
    stack_lvl_2()


try:
    stack_lvl_1()
except Exception as exc:
    tb = traceback.TracebackException.from_exception(exc)

print('Handled at stack lvl 0')
print(''.join(tb.stack.format()))

结果是:

Handled at stack lvl 0
  File "exc.py", line 17, in <module>
    stack_lvl_1()
  File "exc.py", line 13, in stack_lvl_1
    stack_lvl_2()
  File "exc.py", line 9, in stack_lvl_2
    stack_lvl_3()
  File "exc.py", line 5, in stack_lvl_3
    raise Exception('a1', 'b2', 'c3')

注意,堆栈打印不同,缺少第一行和最后一行。因为是不同的format()

截取该异常离生成点越远越好,这使得代码更简单,同时也提供了更多信息。

I don’t see this mentioned in any of the other answers. If you’re passing around an Exception object for whatever reason…

In Python 3.5+ you can get a trace from an Exception object using traceback.TracebackException.from_exception(). For example:

import traceback


def stack_lvl_3():
    raise Exception('a1', 'b2', 'c3')


def stack_lvl_2():
    try:
        stack_lvl_3()
    except Exception as e:
        # raise
        return e


def stack_lvl_1():
    e = stack_lvl_2()
    return e

e = stack_lvl_1()

tb1 = traceback.TracebackException.from_exception(e)
print(''.join(tb1.format()))

However, the above code results in:

Traceback (most recent call last):
  File "exc.py", line 10, in stack_lvl_2
    stack_lvl_3()
  File "exc.py", line 5, in stack_lvl_3
    raise Exception('a1', 'b2', 'c3')
Exception: ('a1', 'b2', 'c3')

This is just two levels of the stack, as opposed to what would have been printed on screen had the exception been raised in stack_lvl_2() and not intercepted (uncomment the # raise line).

As I understand it, that’s because an exception records only the current level of the stack when it is raised, stack_lvl_3() in this case. As it’s passed back up through the stack, more levels are being added to its __traceback__. But we intercepted it in stack_lvl_2(), meaning all it got to record was levels 3 and 2. To get the full trace as printed on stdout we’d have to catch it at the highest (lowest?) level:

import traceback


def stack_lvl_3():
    raise Exception('a1', 'b2', 'c3')


def stack_lvl_2():
    stack_lvl_3()


def stack_lvl_1():
    stack_lvl_2()


try:
    stack_lvl_1()
except Exception as exc:
    tb = traceback.TracebackException.from_exception(exc)

print('Handled at stack lvl 0')
print(''.join(tb.stack.format()))

Which results in:

Handled at stack lvl 0
  File "exc.py", line 17, in <module>
    stack_lvl_1()
  File "exc.py", line 13, in stack_lvl_1
    stack_lvl_2()
  File "exc.py", line 9, in stack_lvl_2
    stack_lvl_3()
  File "exc.py", line 5, in stack_lvl_3
    raise Exception('a1', 'b2', 'c3')

Notice that the stack print is different, the first and last lines are missing. Because it’s a different format().

Intercepting the exception as far away from the point where it was raised as possible makes for simpler code while also giving more information.


回答 10

您需要回溯模块。它可以让您像Python通常一样打印堆栈转储。特别是,print_last函数将打印最后的异常和堆栈跟踪。

You want the traceback module. It will let you print stack dumps like Python normally does. In particular, the print_last function will print the last exception and a stack trace.


回答 11

从异常对象以字符串形式获取完整的追溯 traceback.format_exception

如果只有异常对象,则可以使用以下命令从Python 3中的代码的任何点以字符串形式获取跟踪:

import traceback

''.join(traceback.format_exception(None, exc_obj, exc_obj.__traceback__))

完整示例:

#!/usr/bin/env python3

import traceback

def f():
    g()

def g():
    raise Exception('asdf')

try:
    g()
except Exception as e:
    exc = e

tb_str = ''.join(traceback.format_exception(None, exc_obj, exc_obj.__traceback__))
print(tb_str)

输出:

Traceback (most recent call last):
  File "./main.py", line 12, in <module>
    g()
  File "./main.py", line 9, in g
    raise Exception('asdf')
Exception: asdf

文档:https : //docs.python.org/3.7/library/traceback.html#traceback.format_exception

另请参阅:从异常对象中提取回溯信息

在Python 3.7.3中测试。

Get the full traceback as a string from the exception object with traceback.format_exception

If you only have the exception object, you can get the traceback as a string from any point of the code in Python 3 with:

import traceback

''.join(traceback.format_exception(None, exc_obj, exc_obj.__traceback__))

Full example:

#!/usr/bin/env python3

import traceback

def f():
    g()

def g():
    raise Exception('asdf')

try:
    g()
except Exception as e:
    exc = e

tb_str = ''.join(traceback.format_exception(None, exc_obj, exc_obj.__traceback__))
print(tb_str)

Output:

Traceback (most recent call last):
  File "./main.py", line 12, in <module>
    g()
  File "./main.py", line 9, in g
    raise Exception('asdf')
Exception: asdf

Documentation: https://docs.python.org/3.7/library/traceback.html#traceback.format_exception

See also: Extract traceback info from an exception object

Tested in Python 3.7.3.


回答 12

如果您已经有一个Error对象,并且想要打印整个内容,则需要进行以下稍微尴尬的调用:

import traceback
traceback.print_exception(type(err), err, err.__traceback__)

是的,print_exception需要三个位置参数:异常的类型,实际的异常对象以及异常自己的内部回溯属性。

在python 3.5或更高版本中,type(err)是可选的…但是它是一个位置参数,因此您仍然必须在其位置显式传递None。

traceback.print_exception(None, err, err.__traceback__)

我不知道为什么所有这些都不是唯一的traceback.print_exception(err)。为什么您要打印出错误以及与该错误无关的回溯,这超出了我的范围。

If you have an Error object already, and you want to print the whole thing, you need to make this slightly awkward call:

import traceback
traceback.print_exception(type(err), err, err.__traceback__)

That’s right, print_exception takes three positional arguments: The type of the exception, the actual exception object, and the exception’s own internal traceback property.

In python 3.5 or later, the type(err) is optional… but it’s a positional argument, so you still have to explicitly pass None in its place.

traceback.print_exception(None, err, err.__traceback__)

I have no idea why all of this isn’t just traceback.print_exception(err). Why you would ever want to print out an error, along with a traceback other than the one that belongs to that error, is beyond me.


您如何测试Python函数引发异常?

问题:您如何测试Python函数引发异常?

如何编写仅在函数未引发预期异常的情况下失败的单元测试?

How does one write a unittest that fails only if a function doesn’t throw an expected exception?


回答 0

使用unittest模块中的TestCase.assertRaises(或TestCase.failUnlessRaises),例如:

import mymod

class MyTestCase(unittest.TestCase):
    def test1(self):
        self.assertRaises(SomeCoolException, mymod.myfunc)

Use TestCase.assertRaises (or TestCase.failUnlessRaises) from the unittest module, for example:

import mymod

class MyTestCase(unittest.TestCase):
    def test1(self):
        self.assertRaises(SomeCoolException, mymod.myfunc)

回答 1

从Python 2.7开始,您可以使用上下文管理器来获取抛出的实际Exception对象:

import unittest

def broken_function():
    raise Exception('This is broken')

class MyTestCase(unittest.TestCase):
    def test(self):
        with self.assertRaises(Exception) as context:
            broken_function()

        self.assertTrue('This is broken' in context.exception)

if __name__ == '__main__':
    unittest.main()

http://docs.python.org/dev/library/unittest.html#unittest.TestCase.assertRaises


Python的3.5,你必须包装context.exceptionstr,否则,你会得到一个TypeError

self.assertTrue('This is broken' in str(context.exception))

Since Python 2.7 you can use context manager to get ahold of the actual Exception object thrown:

import unittest

def broken_function():
    raise Exception('This is broken')

class MyTestCase(unittest.TestCase):
    def test(self):
        with self.assertRaises(Exception) as context:
            broken_function()

        self.assertTrue('This is broken' in context.exception)

if __name__ == '__main__':
    unittest.main()

http://docs.python.org/dev/library/unittest.html#unittest.TestCase.assertRaises


In Python 3.5, you have to wrap context.exception in str, otherwise you’ll get a TypeError

self.assertTrue('This is broken' in str(context.exception))

回答 2

我上一个答案中的代码可以简化为:

def test_afunction_throws_exception(self):
    self.assertRaises(ExpectedException, afunction)

如果函数接受参数,则将它们传递给assertRaises,如下所示:

def test_afunction_throws_exception(self):
    self.assertRaises(ExpectedException, afunction, arg1, arg2)

The code in my previous answer can be simplified to:

def test_afunction_throws_exception(self):
    self.assertRaises(ExpectedException, afunction)

And if afunction takes arguments, just pass them into assertRaises like this:

def test_afunction_throws_exception(self):
    self.assertRaises(ExpectedException, afunction, arg1, arg2)

回答 3

您如何测试Python函数引发异常?

如何编写仅在函数未引发预期异常的情况下失败的测试?

简短答案:

将该self.assertRaises方法用作上下文管理器:

    def test_1_cannot_add_int_and_str(self):
        with self.assertRaises(TypeError):
            1 + '1'

示范

最佳实践方法相当容易在Python Shell中进行演示。

unittest

在Python 2.7或3中:

import unittest

在Python 2.6中,您可以安装2.7 unittest库的向后移植,称为unittest2,并将其别名为unittest

import unittest2 as unittest

测试示例

现在,将以下Python类型安全性测试粘贴到您的Python Shell中:

class MyTestCase(unittest.TestCase):
    def test_1_cannot_add_int_and_str(self):
        with self.assertRaises(TypeError):
            1 + '1'
    def test_2_cannot_add_int_and_str(self):
        import operator
        self.assertRaises(TypeError, operator.add, 1, '1')

测试人员assertRaises用作上下文管理器,以确保在记录错误的同时正确捕获并清除该错误。

我们也可以使用上下文管理器来编写它,请参阅测试二。第一个参数是您希望引发的错误类型,第二个参数是您要测试的函数,其余的args和关键字args将传递给该函数。

我认为仅使用上下文管理器就更加简单,可读性和可维护性。

运行测试

要运行测试:

unittest.main(exit=False)

在Python 2.6中,您可能需要以下内容

unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromTestCase(MyTestCase))

并且您的终端应输出以下内容:

..
----------------------------------------------------------------------
Ran 2 tests in 0.007s

OK
<unittest2.runner.TextTestResult run=2 errors=0 failures=0>

然后,正如我们期望的那样,尝试在中添加1'1'结果TypeError


有关更详细的输出,请尝试以下操作:

unittest.TextTestRunner(verbosity=2).run(unittest.TestLoader().loadTestsFromTestCase(MyTestCase))

How do you test that a Python function throws an exception?

How does one write a test that fails only if a function doesn’t throw an expected exception?

Short Answer:

Use the self.assertRaises method as a context manager:

    def test_1_cannot_add_int_and_str(self):
        with self.assertRaises(TypeError):
            1 + '1'

Demonstration

The best practice approach is fairly easy to demonstrate in a Python shell.

The unittest library

In Python 2.7 or 3:

import unittest

In Python 2.6, you can install a backport of 2.7’s unittest library, called unittest2, and just alias that as unittest:

import unittest2 as unittest

Example tests

Now, paste into your Python shell the following test of Python’s type-safety:

class MyTestCase(unittest.TestCase):
    def test_1_cannot_add_int_and_str(self):
        with self.assertRaises(TypeError):
            1 + '1'
    def test_2_cannot_add_int_and_str(self):
        import operator
        self.assertRaises(TypeError, operator.add, 1, '1')

Test one uses assertRaises as a context manager, which ensures that the error is properly caught and cleaned up, while recorded.

We could also write it without the context manager, see test two. The first argument would be the error type you expect to raise, the second argument, the function you are testing, and the remaining args and keyword args will be passed to that function.

I think it’s far more simple, readable, and maintainable to just to use the context manager.

Running the tests

To run the tests:

unittest.main(exit=False)

In Python 2.6, you’ll probably need the following:

unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromTestCase(MyTestCase))

And your terminal should output the following:

..
----------------------------------------------------------------------
Ran 2 tests in 0.007s

OK
<unittest2.runner.TextTestResult run=2 errors=0 failures=0>

And we see that as we expect, attempting to add a 1 and a '1' result in a TypeError.


For more verbose output, try this:

unittest.TextTestRunner(verbosity=2).run(unittest.TestLoader().loadTestsFromTestCase(MyTestCase))

回答 4

您的代码应遵循以下模式(这是一个unittest模块样式测试):

def test_afunction_throws_exception(self):
    try:
        afunction()
    except ExpectedException:
        pass
    except Exception:
       self.fail('unexpected exception raised')
    else:
       self.fail('ExpectedException not raised')

在Python <2.7上,此构造对于检查预期异常中的特定值很有用。unittest函数assertRaises仅检查是否引发了异常。

Your code should follow this pattern (this is a unittest module style test):

def test_afunction_throws_exception(self):
    try:
        afunction()
    except ExpectedException:
        pass
    except Exception:
       self.fail('unexpected exception raised')
    else:
       self.fail('ExpectedException not raised')

On Python < 2.7 this construct is useful for checking for specific values in the expected exception. The unittest function assertRaises only checks if an exception was raised.


回答 5

来自:http : //www.lengrand.fr/2011/12/pythonunittest-assertraises-raises-error/

首先,这是文件dum_function.py中相应的(still dum:p)函数:

def square_value(a):
   """
   Returns the square value of a.
   """
   try:
       out = a*a
   except TypeError:
       raise TypeError("Input should be a string:")

   return out

这是要执行的测试(仅插入此测试):

import dum_function as df # import function module
import unittest
class Test(unittest.TestCase):
   """
      The class inherits from unittest
      """
   def setUp(self):
       """
       This method is called before each test
       """
       self.false_int = "A"

   def tearDown(self):
       """
       This method is called after each test
       """
       pass
      #---
         ## TESTS
   def test_square_value(self):
       # assertRaises(excClass, callableObj) prototype
       self.assertRaises(TypeError, df.square_value(self.false_int))

   if __name__ == "__main__":
       unittest.main()

现在我们准备测试我们的功能!这是尝试运行测试时发生的情况:

======================================================================
ERROR: test_square_value (__main__.Test)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_dum_function.py", line 22, in test_square_value
    self.assertRaises(TypeError, df.square_value(self.false_int))
  File "/home/jlengrand/Desktop/function.py", line 8, in square_value
    raise TypeError("Input should be a string:")
TypeError: Input should be a string:

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (errors=1)

TypeError被引发actullay,并生成测试失败。问题在于,这正是我们想要的行为:s。

为避免此错误,只需在测试调用中使用lambda运行该函数:

self.assertRaises(TypeError, lambda: df.square_value(self.false_int))

最终输出:

----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

太好了!

…对我来说也是完美的!

非常感谢Julien Lengrand-Lambert先生


这个测试断言实际上返回一个假阳性。发生这种情况是因为’assertRaises’内部的lambda是引发类型错误而不是经过测试的函数的单位。

from: http://www.lengrand.fr/2011/12/pythonunittest-assertraises-raises-error/

First, here is the corresponding (still dum :p) function in file dum_function.py :

def square_value(a):
   """
   Returns the square value of a.
   """
   try:
       out = a*a
   except TypeError:
       raise TypeError("Input should be a string:")

   return out

Here is the test to be performed (only this test is inserted):

import dum_function as df # import function module
import unittest
class Test(unittest.TestCase):
   """
      The class inherits from unittest
      """
   def setUp(self):
       """
       This method is called before each test
       """
       self.false_int = "A"

   def tearDown(self):
       """
       This method is called after each test
       """
       pass
      #---
         ## TESTS
   def test_square_value(self):
       # assertRaises(excClass, callableObj) prototype
       self.assertRaises(TypeError, df.square_value(self.false_int))

   if __name__ == "__main__":
       unittest.main()

We are now ready to test our function! Here is what happens when trying to run the test :

======================================================================
ERROR: test_square_value (__main__.Test)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_dum_function.py", line 22, in test_square_value
    self.assertRaises(TypeError, df.square_value(self.false_int))
  File "/home/jlengrand/Desktop/function.py", line 8, in square_value
    raise TypeError("Input should be a string:")
TypeError: Input should be a string:

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (errors=1)

The TypeError is actullay raised, and generates a test failure. The problem is that this is exactly the behavior we wanted :s.

To avoid this error, simply run the function using lambda in the test call :

self.assertRaises(TypeError, lambda: df.square_value(self.false_int))

The final output :

----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

Perfect !

… and for me is perfect too!!

Thansk a lot Mr. Julien Lengrand-Lambert


This test assert actually returns a false positive. That happens because the lambda inside the ‘assertRaises’ is the unit that raises type error and not the tested function.


回答 6

您可以构建自己的程序contextmanager来检查是否引发了异常。

import contextlib

@contextlib.contextmanager
def raises(exception):
    try:
        yield 
    except exception as e:
        assert True
    else:
        assert False

然后您可以raises像这样使用:

with raises(Exception):
    print "Hola"  # Calls assert False

with raises(Exception):
    raise Exception  # Calls assert True

如果您使用pytest,则该东西已经实现。您可以pytest.raises(Exception)

例:

def test_div_zero():
    with pytest.raises(ZeroDivisionError):
        1/0

结果:

pigueiras@pigueiras$ py.test
================= test session starts =================
platform linux2 -- Python 2.6.6 -- py-1.4.20 -- pytest-2.5.2 -- /usr/bin/python
collected 1 items 

tests/test_div_zero.py:6: test_div_zero PASSED

You can build your own contextmanager to check if the exception was raised.

import contextlib

@contextlib.contextmanager
def raises(exception):
    try:
        yield 
    except exception as e:
        assert True
    else:
        assert False

And then you can use raises like this:

with raises(Exception):
    print "Hola"  # Calls assert False

with raises(Exception):
    raise Exception  # Calls assert True

If you are using pytest, this thing is implemented already. You can do pytest.raises(Exception):

Example:

def test_div_zero():
    with pytest.raises(ZeroDivisionError):
        1/0

And the result:

pigueiras@pigueiras$ py.test
================= test session starts =================
platform linux2 -- Python 2.6.6 -- py-1.4.20 -- pytest-2.5.2 -- /usr/bin/python
collected 1 items 

tests/test_div_zero.py:6: test_div_zero PASSED

回答 7

我几乎在所有地方都使用doctest [1],因为我喜欢同时记录和测试函数的事实。

看一下这段代码:

def throw_up(something, gowrong=False):
    """
    >>> throw_up('Fish n Chips')
    Traceback (most recent call last):
    ...
    Exception: Fish n Chips

    >>> throw_up('Fish n Chips', gowrong=True)
    'I feel fine!'
    """
    if gowrong:
        return "I feel fine!"
    raise Exception(something)

if __name__ == '__main__':
    import doctest
    doctest.testmod()

如果将此示例放在模块中并从命令行运行它,则将评估并检查两个测试用例。

[1] Python文档:23.2 doctest-测试交互式Python示例

I use doctest[1] almost everywhere because I like the fact that I document and test my functions at the same time.

Have a look at this code:

def throw_up(something, gowrong=False):
    """
    >>> throw_up('Fish n Chips')
    Traceback (most recent call last):
    ...
    Exception: Fish n Chips

    >>> throw_up('Fish n Chips', gowrong=True)
    'I feel fine!'
    """
    if gowrong:
        return "I feel fine!"
    raise Exception(something)

if __name__ == '__main__':
    import doctest
    doctest.testmod()

If you put this example in a module and run it from the command line both test cases are evaluated and checked.

[1] Python documentation: 23.2 doctest — Test interactive Python examples


回答 8

我刚刚发现,Mock库提供了assertRaisesWithMessage()方法(在其unittest.TestCase子类中),该方法不仅会检查是否引发了预期的异常,还检查了与预期消息一起引发的异常:

from testcase import TestCase

import mymod

class MyTestCase(TestCase):
    def test1(self):
        self.assertRaisesWithMessage(SomeCoolException,
                                     'expected message',
                                     mymod.myfunc)

I just discovered that the Mock library provides an assertRaisesWithMessage() method (in its unittest.TestCase subclass), which will check not only that the expected exception is raised, but also that it is raised with the expected message:

from testcase import TestCase

import mymod

class MyTestCase(TestCase):
    def test1(self):
        self.assertRaisesWithMessage(SomeCoolException,
                                     'expected message',
                                     mymod.myfunc)

回答 9

这里有很多答案。该代码显示了我们如何创建一个异常,如何在我们的方法中使用该异常,最后,您如何在单元测试中进行验证,并提出正确的异常。

import unittest

class DeviceException(Exception):
    def __init__(self, msg, code):
        self.msg = msg
        self.code = code
    def __str__(self):
        return repr("Error {}: {}".format(self.code, self.msg))

class MyDevice(object):
    def __init__(self):
        self.name = 'DefaultName'

    def setParameter(self, param, value):
        if isinstance(value, str):
            setattr(self, param , value)
        else:
            raise DeviceException('Incorrect type of argument passed. Name expects a string', 100001)

    def getParameter(self, param):
        return getattr(self, param)

class TestMyDevice(unittest.TestCase):

    def setUp(self):
        self.dev1 = MyDevice()

    def tearDown(self):
        del self.dev1

    def test_name(self):
        """ Test for valid input for name parameter """

        self.dev1.setParameter('name', 'MyDevice')
        name = self.dev1.getParameter('name')
        self.assertEqual(name, 'MyDevice')

    def test_invalid_name(self):
        """ Test to check if error is raised if invalid type of input is provided """

        self.assertRaises(DeviceException, self.dev1.setParameter, 'name', 1234)

    def test_exception_message(self):
        """ Test to check if correct exception message and code is raised when incorrect value is passed """

        with self.assertRaises(DeviceException) as cm:
            self.dev1.setParameter('name', 1234)
        self.assertEqual(cm.exception.msg, 'Incorrect type of argument passed. Name expects a string', 'mismatch in expected error message')
        self.assertEqual(cm.exception.code, 100001, 'mismatch in expected error code')


if __name__ == '__main__':
    unittest.main()

There are a lot of answers here. The code shows how we can create an Exception, how we can use that exception in our methods, and finally, how you can verify in a unit test, the correct exceptions being raised.

import unittest

class DeviceException(Exception):
    def __init__(self, msg, code):
        self.msg = msg
        self.code = code
    def __str__(self):
        return repr("Error {}: {}".format(self.code, self.msg))

class MyDevice(object):
    def __init__(self):
        self.name = 'DefaultName'

    def setParameter(self, param, value):
        if isinstance(value, str):
            setattr(self, param , value)
        else:
            raise DeviceException('Incorrect type of argument passed. Name expects a string', 100001)

    def getParameter(self, param):
        return getattr(self, param)

class TestMyDevice(unittest.TestCase):

    def setUp(self):
        self.dev1 = MyDevice()

    def tearDown(self):
        del self.dev1

    def test_name(self):
        """ Test for valid input for name parameter """

        self.dev1.setParameter('name', 'MyDevice')
        name = self.dev1.getParameter('name')
        self.assertEqual(name, 'MyDevice')

    def test_invalid_name(self):
        """ Test to check if error is raised if invalid type of input is provided """

        self.assertRaises(DeviceException, self.dev1.setParameter, 'name', 1234)

    def test_exception_message(self):
        """ Test to check if correct exception message and code is raised when incorrect value is passed """

        with self.assertRaises(DeviceException) as cm:
            self.dev1.setParameter('name', 1234)
        self.assertEqual(cm.exception.msg, 'Incorrect type of argument passed. Name expects a string', 'mismatch in expected error message')
        self.assertEqual(cm.exception.code, 100001, 'mismatch in expected error code')


if __name__ == '__main__':
    unittest.main()

回答 10

您可以使用unittest模块中的assertRaises

import unittest

class TestClass():
  def raises_exception(self):
    raise Exception("test")

class MyTestCase(unittest.TestCase):
  def test_if_method_raises_correct_exception(self):
    test_class = TestClass()
    # note that you dont use () when passing the method to assertRaises
    self.assertRaises(Exception, test_class.raises_exception)

You can use assertRaises from the unittest module

import unittest

class TestClass():
  def raises_exception(self):
    raise Exception("test")

class MyTestCase(unittest.TestCase):
  def test_if_method_raises_correct_exception(self):
    test_class = TestClass()
    # note that you dont use () when passing the method to assertRaises
    self.assertRaises(Exception, test_class.raises_exception)

回答 11

尽管所有答案都很好,但我仍在寻找一种方法来测试函数是否引发异常,而无需依赖于单元测试框架和编写测试类。

我最终写了以下内容:

def assert_error(e, x):
    try:
        e(x)
    except:
        return
    raise AssertionError()

def failing_function(x):
    raise ValueError()

def dummy_function(x):
    return x

if __name__=="__main__":
    assert_error(failing_function, 0)
    assert_error(dummy_function, 0)

它在正确的行失败:

Traceback (most recent call last):
  File "assert_error.py", line 16, in <module>
    assert_error(dummy_function, 0)
  File "assert_error.py", line 6, in assert_error
    raise AssertionError()
AssertionError

While all the answers are perfectly fine, I was looking for a way to test if a function raised an exception without relying on unit testing frameworks and having to write test classes.

I ended up writing the following:

def assert_error(e, x):
    try:
        e(x)
    except:
        return
    raise AssertionError()

def failing_function(x):
    raise ValueError()

def dummy_function(x):
    return x

if __name__=="__main__":
    assert_error(failing_function, 0)
    assert_error(dummy_function, 0)

And it fails on the right line :

Traceback (most recent call last):
  File "assert_error.py", line 16, in <module>
    assert_error(dummy_function, 0)
  File "assert_error.py", line 6, in assert_error
    raise AssertionError()
AssertionError

关于捕获任何异常

问题:关于捕获任何异常

我如何编写一个try/ except块来捕获所有异常?

How can I write a try/except block that catches all exceptions?


回答 0

您可以,但您可能不应该:

try:
    do_something()
except:
    print "Caught it!"

但是,这也会捕获类似的异常KeyboardInterrupt,您通常不希望那样,对吗?除非您立即重新引发异常-参见docs中的以下示例:

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
except IOError as (errno, strerror):
    print "I/O error({0}): {1}".format(errno, strerror)
except ValueError:
    print "Could not convert data to an integer."
except:
    print "Unexpected error:", sys.exc_info()[0]
    raise

You can but you probably shouldn’t:

try:
    do_something()
except:
    print "Caught it!"

However, this will also catch exceptions like KeyboardInterrupt and you usually don’t want that, do you? Unless you re-raise the exception right away – see the following example from the docs:

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
except IOError as (errno, strerror):
    print "I/O error({0}): {1}".format(errno, strerror)
except ValueError:
    print "Could not convert data to an integer."
except:
    print "Unexpected error:", sys.exc_info()[0]
    raise

回答 1

除了裸露的except:子句(就像其他人说的那样,您不应该使用),您可以简单地捕获Exception

import traceback
import logging

try:
    whatever()
except Exception as e:
    logging.error(traceback.format_exc())
    # Logs the error appropriately. 

通常,仅当您想在终止之前处理任何其他未捕获的异常时,才通常考虑在代码的最外层执行此操作。

的优势,except Exception在裸露的except是,有少数exceptions,它不会赶上,最明显KeyboardInterruptSystemExit:如果你抓住了,吞下这些,那么你可以让任何人都很难离开你的脚本。

Apart from a bare except: clause (which as others have said you shouldn’t use), you can simply catch Exception:

import traceback
import logging

try:
    whatever()
except Exception as e:
    logging.error(traceback.format_exc())
    # Logs the error appropriately. 

You would normally only ever consider doing this at the outermost level of your code if for example you wanted to handle any otherwise uncaught exceptions before terminating.

The advantage of except Exception over the bare except is that there are a few exceptions that it wont catch, most obviously KeyboardInterrupt and SystemExit: if you caught and swallowed those then you could make it hard for anyone to exit your script.


回答 2

您可以执行此操作以处理一般异常

try:
    a = 2/0
except Exception as e:
    print e.__doc__
    print e.message

You can do this to handle general exceptions

try:
    a = 2/0
except Exception as e:
    print e.__doc__
    print e.message

回答 3

要捕获所有可能的异常,请捕获BaseException。它位于Exception层次结构的顶部:

Python 3:https//docs.python.org/3.5/library/exceptions.html#exception-hierarchy

Python 2.7:https//docs.python.org/2.7/library/exceptions.html#exception-hierarchy

try:
    something()
except BaseException as error:
    print('An exception occurred: {}'.format(error))

但是,正如其他人所提到的那样,通常仅在特定情况下才需要此功能。

To catch all possible exceptions, catch BaseException. It’s on top of the Exception hierarchy:

Python 3: https://docs.python.org/3.5/library/exceptions.html#exception-hierarchy

Python 2.7: https://docs.python.org/2.7/library/exceptions.html#exception-hierarchy

try:
    something()
except BaseException as error:
    print('An exception occurred: {}'.format(error))

But as other people mentioned, you would usually not need this, only for specific cases.


回答 4

非常简单的示例,类似于此处找到的示例:

http://docs.python.org/tutorial/errors.html#defining-clean-up-actions

如果您尝试捕获所有异常,则将所有代码放在“ try:”语句中,代替“ print”执行可能会引发异常的操作。”。

try:
    print "Performing an action which may throw an exception."
except Exception, error:
    print "An exception was thrown!"
    print str(error)
else:
    print "Everything looks great!"
finally:
    print "Finally is called directly after executing the try statement whether an exception is thrown or not."

在上面的示例中,您将按以下顺序查看输出:

1)执行可能会引发异常的动作。

2)无论是否引发异常,在执行try语句后直接调用final。

3)“引发了异常!” 或“一切看起来都很棒!” 取决于是否引发异常。

希望这可以帮助!

Very simple example, similar to the one found here:

http://docs.python.org/tutorial/errors.html#defining-clean-up-actions

If you’re attempting to catch ALL exceptions, then put all your code within the “try:” statement, in place of ‘print “Performing an action which may throw an exception.”‘.

try:
    print "Performing an action which may throw an exception."
except Exception, error:
    print "An exception was thrown!"
    print str(error)
else:
    print "Everything looks great!"
finally:
    print "Finally is called directly after executing the try statement whether an exception is thrown or not."

In the above example, you’d see output in this order:

1) Performing an action which may throw an exception.

2) Finally is called directly after executing the try statement whether an exception is thrown or not.

3) “An exception was thrown!” or “Everything looks great!” depending on whether an exception was thrown.

Hope this helps!


回答 5

有多种方法可以做到这一点,特别是在Python 3.0及更高版本中

方法1

这是简单的方法,但不建议使用,因为您不知道确切的代码行实际引发异常:

def bad_method():
    try:
        sqrt = 0**-1
    except Exception as e:
        print(e)

bad_method()

方法2

建议使用此方法,因为它提供了有关每个异常的更多详细信息。这包括:

  • 您代码的行号
  • 文件名
  • 实际错误更详细

唯一的缺点是需要导入tracback。

import traceback

def bad_method():
    try:
        sqrt = 0**-1
    except Exception:
        print(traceback.print_exc())

bad_method()

There are multiple ways to do this in particular with Python 3.0 and above

Approach 1

This is simple approach but not recommended because you would not know exactly which line of code is actually throwing the exception:

def bad_method():
    try:
        sqrt = 0**-1
    except Exception as e:
        print(e)

bad_method()

Approach 2

This approach is recommended because it provides more detail about each exception. It includes:

  • Line number for your code
  • File name
  • The actual error in more verbose way

The only drawback is tracback needs to be imported.

import traceback

def bad_method():
    try:
        sqrt = 0**-1
    except Exception:
        print(traceback.print_exc())

bad_method()

回答 6

我刚刚发现了这个小技巧,可以测试Python 2.7中的异常名称。有时我已经在代码中处理了特定的异常,因此我需要进行测试以查看该名称是否在已处理的异常列表中。

try:
    raise IndexError #as test error
except Exception as e:
    excepName = type(e).__name__ # returns the name of the exception

I’ve just found out this little trick for testing if exception names in Python 2.7 . Sometimes i have handled specific exceptions in the code, so i needed a test to see if that name is within a list of handled exceptions.

try:
    raise IndexError #as test error
except Exception as e:
    excepName = type(e).__name__ # returns the name of the exception

回答 7

try:
    whatever()
except:
    # this will catch any exception or error

值得一提的是,这不是正确的Python编码。这还将捕获许多您可能不想捕获的错误。

try:
    whatever()
except:
    # this will catch any exception or error

It is worth mentioning this is not proper Python coding. This will catch also many errors you might not want to catch.


在一行中捕获多个异常(块除外)

问题:在一行中捕获多个异常(块除外)

我知道我可以做到:

try:
    # do something that may fail
except:
    # do this if ANYTHING goes wrong

我也可以这样做:

try:
    # do something that may fail
except IDontLikeYouException:
    # say please
except YouAreTooShortException:
    # stand on a ladder

但是,如果我想在两个不同的异常中做同样的事情,那么我现在想到的最好的方法就是:

try:
    # do something that may fail
except IDontLikeYouException:
    # say please
except YouAreBeingMeanException:
    # say please

有什么办法可以做这样的事情(因为在两种情况下都要采取的行动是say please):

try:
    # do something that may fail
except IDontLikeYouException, YouAreBeingMeanException:
    # say please

现在,这确实不起作用,因为它与以下语法匹配:

try:
    # do something that may fail
except Exception, e:
    # say please

因此,我捕捉两个截然不同的异常的努力并未完全实现。

有没有办法做到这一点?

I know that I can do:

try:
    # do something that may fail
except:
    # do this if ANYTHING goes wrong

I can also do this:

try:
    # do something that may fail
except IDontLikeYouException:
    # say please
except YouAreTooShortException:
    # stand on a ladder

But if I want to do the same thing inside two different exceptions, the best I can think of right now is to do this:

try:
    # do something that may fail
except IDontLikeYouException:
    # say please
except YouAreBeingMeanException:
    # say please

Is there any way that I can do something like this (since the action to take in both exceptions is to say please):

try:
    # do something that may fail
except IDontLikeYouException, YouAreBeingMeanException:
    # say please

Now this really won’t work, as it matches the syntax for:

try:
    # do something that may fail
except Exception, e:
    # say please

So, my effort to catch the two distinct exceptions doesn’t exactly come through.

Is there a way to do this?


回答 0

Python文档

例如,except子句可以将多个异常命名为带括号的元组。

except (IDontLikeYouException, YouAreBeingMeanException) as e:
    pass

或者,仅对于Python 2:

except (IDontLikeYouException, YouAreBeingMeanException), e:
    pass

用逗号将变量与变量分开仍然可以在Python 2.6和2.7中使用,但是现在已弃用,并且在Python 3中不起作用。现在您应该使用as

From Python Documentation:

An except clause may name multiple exceptions as a parenthesized tuple, for example

except (IDontLikeYouException, YouAreBeingMeanException) as e:
    pass

Or, for Python 2 only:

except (IDontLikeYouException, YouAreBeingMeanException), e:
    pass

Separating the exception from the variable with a comma will still work in Python 2.6 and 2.7, but is now deprecated and does not work in Python 3; now you should be using as.


回答 1

如何在一行中捕获多个异常(块除外)

做这个:

try:
    may_raise_specific_errors():
except (SpecificErrorOne, SpecificErrorTwo) as error:
    handle(error) # might log or have some other default behavior...

由于使用了逗号将错误对象分配给名称的较旧语法,因此需要使用括号。该as关键字用于分配。您可以为错误对象使用任何名称,我error个人更喜欢。

最佳实践

要以当前方式并与Python向前兼容的方式执行此操作,您需要使用逗号分隔Exceptions,并用括号将其包裹起来,以区别于早期的语法,后者通过遵循用逗号。

这是一个简单用法的示例:

import sys

try:
    mainstuff()
except (KeyboardInterrupt, EOFError): # the parens are necessary
    sys.exit(0)

我仅指定这些异常以避免隐藏错误,如果遇到错误,我希望从中获得完整的堆栈跟踪。

此处记录:https : //docs.python.org/tutorial/errors.html

您可以将异常分配给变量,(e很常见,但是,如果您需要长时间的异常处理,或者您的IDE像我的一样,仅突出显示比这个更大的选择,那么您可能更喜欢使用更冗长的变量。)实例具有args属性。这是一个例子:

import sys

try:
    mainstuff()
except (KeyboardInterrupt, EOFError) as err: 
    print(err)
    print(err.args)
    sys.exit(0)

请注意,在Python 3中,结束errexcept块时该对象不在范围内。

不推荐使用

您可能会看到用逗号分配错误的代码。不赞成使用此用法,它是Python 2.5及更早版本中唯一可用的形式,并且如果您希望代码与Python 3向前兼容,则应更新语法以使用新形式:

import sys

try:
    mainstuff()
except (KeyboardInterrupt, EOFError), err: # don't do this in Python 2.6+
    print err
    print err.args
    sys.exit(0)

如果在代码库中看到逗号名称分配,并且您正在使用Python 2.5或更高版本,请切换到新的方式来执行此操作,以便在升级时代码保持兼容。

suppress上下文管理器

可接受的答案实际上是最少4行代码:

try:
    do_something()
except (IDontLikeYouException, YouAreBeingMeanException) as e:
    pass

tryexceptpass线可以与单线处理抑制上下文管理器,可以在Python 3.4

from contextlib import suppress

with suppress(IDontLikeYouException, YouAreBeingMeanException):
     do_something()

因此,当您想pass在某些exceptions情况下使用suppress

How do I catch multiple exceptions in one line (except block)

Do this:

try:
    may_raise_specific_errors():
except (SpecificErrorOne, SpecificErrorTwo) as error:
    handle(error) # might log or have some other default behavior...

The parentheses are required due to older syntax that used the commas to assign the error object to a name. The as keyword is used for the assignment. You can use any name for the error object, I prefer error personally.

Best Practice

To do this in a manner currently and forward compatible with Python, you need to separate the Exceptions with commas and wrap them with parentheses to differentiate from earlier syntax that assigned the exception instance to a variable name by following the Exception type to be caught with a comma.

Here’s an example of simple usage:

import sys

try:
    mainstuff()
except (KeyboardInterrupt, EOFError): # the parens are necessary
    sys.exit(0)

I’m specifying only these exceptions to avoid hiding bugs, which if I encounter I expect the full stack trace from.

This is documented here: https://docs.python.org/tutorial/errors.html

You can assign the exception to a variable, (e is common, but you might prefer a more verbose variable if you have long exception handling or your IDE only highlights selections larger than that, as mine does.) The instance has an args attribute. Here is an example:

import sys

try:
    mainstuff()
except (KeyboardInterrupt, EOFError) as err: 
    print(err)
    print(err.args)
    sys.exit(0)

Note that in Python 3, the err object falls out of scope when the except block is concluded.

Deprecated

You may see code that assigns the error with a comma. This usage, the only form available in Python 2.5 and earlier, is deprecated, and if you wish your code to be forward compatible in Python 3, you should update the syntax to use the new form:

import sys

try:
    mainstuff()
except (KeyboardInterrupt, EOFError), err: # don't do this in Python 2.6+
    print err
    print err.args
    sys.exit(0)

If you see the comma name assignment in your codebase, and you’re using Python 2.5 or higher, switch to the new way of doing it so your code remains compatible when you upgrade.

The suppress context manager

The accepted answer is really 4 lines of code, minimum:

try:
    do_something()
except (IDontLikeYouException, YouAreBeingMeanException) as e:
    pass

The try, except, pass lines can be handled in a single line with the suppress context manager, available in Python 3.4:

from contextlib import suppress

with suppress(IDontLikeYouException, YouAreBeingMeanException):
     do_something()

So when you want to pass on certain exceptions, use suppress.


回答 2

Python文档-> 8.3处理异常

一条try语句可能具有多个except子句,以指定不同异常的处理程序。最多将执行一个处理程序。处理程序仅处理在相应的try子句中发生的异常,而不处理同一try语句的其他处理程序中的异常。exclude子句可以将多个异常命名为带括号的元组,例如:

except (RuntimeError, TypeError, NameError):
    pass

请注意,必须在该元组周围加上括号,因为除了ValueError, e:用于except ValueError as e:现代Python中通常编写的语法(如下所述)外,其他语法都是这样。为了向后兼容,仍旧支持旧语法。这意味着except RuntimeError, TypeError不等于 except (RuntimeError, TypeError):except RuntimeError as TypeError:不是您想要的。

From Python documentation -> 8.3 Handling Exceptions:

A try statement may have more than one except clause, to specify handlers for different exceptions. At most one handler will be executed. Handlers only handle exceptions that occur in the corresponding try clause, not in other handlers of the same try statement. An except clause may name multiple exceptions as a parenthesized tuple, for example:

except (RuntimeError, TypeError, NameError):
    pass

Note that the parentheses around this tuple are required, because except ValueError, e: was the syntax used for what is normally written as except ValueError as e: in modern Python (described below). The old syntax is still supported for backwards compatibility. This means except RuntimeError, TypeError is not equivalent to except (RuntimeError, TypeError): but to except RuntimeError as TypeError: which is not what you want.


回答 3

如果您经常使用大量异常,则可以预定义一个元组,因此不必多次重新键入它们。

#This example code is a technique I use in a library that connects with websites to gather data

ConnectErrs  = (URLError, SSLError, SocketTimeoutError, BadStatusLine, ConnectionResetError)

def connect(url, data):
    #do connection and return some data
    return(received_data)

def some_function(var_a, var_b, ...):
    try: o = connect(url, data)
    except ConnectErrs as e:
        #do the recovery stuff
    blah #do normal stuff you would do if no exception occurred

笔记:

  1. 如果您还需要捕获除预定义元组中的异常以外的其他异常,则需要定义另一个except块。

  2. 如果您不能忍受全局变量,请在main()中定义它,并在需要的地方传递它…

If you frequently use a large number of exceptions, you can pre-define a tuple, so you don’t have to re-type them many times.

#This example code is a technique I use in a library that connects with websites to gather data

ConnectErrs  = (URLError, SSLError, SocketTimeoutError, BadStatusLine, ConnectionResetError)

def connect(url, data):
    #do connection and return some data
    return(received_data)

def some_function(var_a, var_b, ...):
    try: o = connect(url, data)
    except ConnectErrs as e:
        #do the recovery stuff
    blah #do normal stuff you would do if no exception occurred

NOTES:

  1. If you, also, need to catch other exceptions than those in the pre-defined tuple, you will need to define another except block.

  2. If you just cannot tolerate a global variable, define it in main() and pass it around where needed…


回答 4

一种方法是..

try:
   You do your operations here;
   ......................
except(Exception1[, Exception2[,...ExceptionN]]]):
   If there is any exception from the given exception list, 
   then execute this block.
   ......................
else:
   If there is no exception then execute this block. 

另一种方法是创建一种方法,该方法执行由except块执行的任务,并在except您编写的所有块中调用它。

try:
   You do your operations here;
   ......................
except Exception1:
    functionname(parameterList)
except Exception2:
    functionname(parameterList)
except Exception3:
    functionname(parameterList)
else:
   If there is no exception then execute this block. 

def functionname( parameters ):
   //your task..
   return [expression]

我知道第二种方法并不是做到这一点的最佳方法,但我只是在说明一些实现此目的的方法。

One of the way to do this is..

try:
   You do your operations here;
   ......................
except(Exception1[, Exception2[,...ExceptionN]]]):
   If there is any exception from the given exception list, 
   then execute this block.
   ......................
else:
   If there is no exception then execute this block. 

and another way is to create method which performs task executed by except block and call it through all of the except block that you write..

try:
   You do your operations here;
   ......................
except Exception1:
    functionname(parameterList)
except Exception2:
    functionname(parameterList)
except Exception3:
    functionname(parameterList)
else:
   If there is no exception then execute this block. 

def functionname( parameters ):
   //your task..
   return [expression]

I know that second one is not the best way to do this, but i’m just showing number of ways to do this thing.