简体   繁体   English

Python程序终止处理异常

[英]Python Program is Terminating on Handled Exception

I am editing the question for clarity. 我正在编辑这个问题是为了清楚。

I created a class in a module that imports MySQLdb. 我在导入MySQLdb的模块中创建了一个类。 I have found that MySQLdb will raise an Exception if the table the user passes to my class does not exist. 我发现如果用户传递给我的类的表不存在,MySQLdb将引发异常。 I am catching that exception, and passing a new one to the client. 我正在捕获该异常,并将新的异常传递给客户端。 But even if the client catches my exception, the program still terminates. 但即使客户端捕获了我的异常,该程序仍然会终止。 I have also tried passing to the client the same Exception MySQLdb is giving my class. 我也试过传递给客户端同样的异常MySQLdb给我的类。

Since the client will be calling my method in a loop, passing in various table names, I don't want the program to choke if the table name is bad. 由于客户端将在循环中调用我的方法,传入各种表名,我不希望程序在表名不好时阻塞。 I'd like the client's iterations to continue to the next valid table name. 我希望客户端的迭代继续下一个有效的表名。 Here is a snippet (tableName is an arg pass in to the method): 这是一个片段(tableName是方法中的arg传递):

In my class/module: 在我的课程/模块中:

self.tableName = tableName
    try:       
        self.cursor.execute("select * from " + self.tableName + ";") #Will raise Exception if the table does not exist.
    except:
        raise MyException("\n*** " + self.tableName + " does not exist. ***")

In the client: 在客户端:

tables = ["BadTableName", "GoodTableNameA", "GoodTableNameB","GoodTableNameC"]

    try:
        for table in tables:
            my_method(table) #Exception message gets passed in with BadTableName, but the program ends. Subsequest iterations of this loop never happen
    except Exception, e:
        print e

I would like the client to continue even after calling my_method(BadTableName). 我希望客户端在调用my_method(BadTableName)之后继续。

By the way, my_method() is part of a class defined in its own module which the client is importing. 顺便说一下,my_method()是客户端导入的自己模块中定义的类的一部分。

Thank you. 谢谢。

Exceptions do not always cause the program to end. 例外并不总是导致程序结束。 From the docs : 来自文档

Errors detected during execution are called exceptions and are not unconditionally fatal: 执行期间检测到的错误称为异常,并非无条件致命:

If an exception is raised in a try: except block and the except clause is specifying the exception or a super class of the exception it will be handled. 如果在try:except块中引发异常并且except子句指定异常或异常的超类,则将处理该异常。

When handling an exception you can inspect it and find out all information related to it. 处理异常时,您可以检查它并找出与其相关的所有信息。 I have never used the traceback module before but it looks like it contains everything you need. 我以前从未使用过traceback模块,但看起来它包含了你需要的一切。

I guess your second question depends on what you want your user to see. 我想你的第二个问题取决于你希望用户看到什么。 Should the exception be shown? 是否应该显示例外情况? (you have access to the traceback). (您可以访问回溯)。 Should just the message be shown? 应该只显示消息吗? SHould you log the traceback? 你应该记录回溯吗?

Adding to the other answers: uncaught exceptions will terminate a program, but only after executing the applicable finally block (if any) and any atexit handlers . 添加到其他答案:未捕获的异常将终止程序,但仅在执行适用的finally (如果有)和任何atexit处理程序之后 So in principle, it is possible to continue execution indefinitely after an uncaught exception. 因此原则上,在未捕获的异常之后可以无限期地继续执行。

There is no class of exceptions that will just print an error message and continue execution by their nature, though. 但是,没有任何类别的异常只打印错误消息并继续按其性质执行。 If you want that, use warnings . 如果您需要,请使用警告

1) No, raising an exception doesn't always cause the program to terminate. 1)不,引发异常并不总是导致程序终止。 Uncaught exceptions cause a program to terminate. 未捕获的异常导致程序终止。 You can surround code with a try/except block, as follows, to stop the exception from propagating up the stack. 您可以使用try/except块包围代码,如下所示,以阻止异常向上传播。

try:
    file = open("foo.txt")
except IOError:
    file = None

2) The code that actually catches the exception has access to the originating stack frame of the exception, and can decide what to do with it. 2)实际捕获异常的代码可以访问异常的原始堆栈帧,并可以决定如何处理它。

Re-raise error with original traceback: 使用原始回溯重新引发错误:

try:
    some_function()
except IOError as e:
    raise

Re-raise error with new traceback (almost never as useful as the first case): 使用新的回溯重新引发错误(几乎从未像第一种情况那样有用):

try:
    some_function()
except IOError as e:
    raise e

Don't re-raise, and print the exception and traceback: 不要重新加注,并打印异常和回溯:

try:
    some_function()
except IOError as e:
    import traceback
    traceback.print_exc()

An uncaught exception will terminate a program. 未捕获的异常将终止程序。 A caught exception will not 被抓住的例外不会

If the exception is caught, the stack trace can be output using the traceback module: 如果捕获到异常,则可以使用traceback模块输出堆栈跟踪:

http://docs.python.org/2/library/traceback.html#traceback-examples http://docs.python.org/2/library/traceback.html#traceback-examples

After reading your edited question, I'm not sure which of two problems you're having. 阅读完编辑的问题后,我不确定你遇到了哪两个问题。


If your problem is just that you just want an exception to only terminate one loop iteration instead of the whole loop, it's just a matter of re-nesting the statements in the obvious way. 如果您的问题仅仅是您只想要一个异常来终止一个循环迭代而不是整个循环,那么只需要以明显的方式重新嵌套语句。 Instead of this: 而不是这个:

try:
    for table in tables:
        my_method(table) #Exception message gets passed in with BadTableName, but the program ends. Subsequest iterations of this loop never happen
except Exception, e:
    print e

Do this: 做这个:

for table in tables:
    try:
        my_method(table) #Exception message gets passed in with BadTableName, but the program ends. Subsequest iterations of this loop never happen
    except Exception, e:
        print e

On the other hand, if the problem is that the client isn't catching the exception, the problem is most likely that your MyException isn't a subclass of Exception . 另一方面,如果问题是客户端没有捕获异常,则问题很可能是您的MyException不是Exception的子类。 There are at least three ways this could happen. 至少有三种方法可以实现。

Since you're using old-style except syntax ( except Exception, e: ) instead of new-style ( except Exception as e: ), you may be using an older Python version that lets you raise classes that don't inherit from BaseException . 由于你使用的是旧式的except语法( except Exception, e: )而不是new-style( except Exception as e: BaseException ,你可能正在使用旧的Python版本,它允许你引发不从BaseException继承的BaseException For example: 例如:

class MyException(object):
    def __init__(self, msg):
        pass

try:
    raise MyException("dsfsdf")
except Exception:
    pass

Depending on your Python version, this may fail to raise the MyException and instead raise a TypeError(' Out[11]: TypeError('exceptions must be old-style classes or derived from BaseException, not MyException') (which will get caught), or print a warning, or just silently "work" as you asked it to (meaning you don't catch anything, and your program quits with a traceback). 根据您的Python版本,这可能无法引发MyException而是引发TypeError(' Out[11]: TypeError('exceptions must be old-style classes or derived from BaseException, not MyException') (将被捕获) ,或者打印一个警告,或者只是按照你的要求默默地“工作”(这意味着你没有抓到任何东西,并且你的程序退出了追溯)。


Meanwhile, even in 2.7, you can still raise old-style classes, which also won't get caught: 同时,即使在2.7中,你仍然可以提升旧式课程,这也不会被抓住:

class MyException:
    def __init__(self, msg):
        pass

try:
    raise MyException("dsfsdf")
except Exception:
    pass

This will always fail to catch the exception, and your app will quit with a traceback. 这将总是无法捕获异常,您的应用程序将退出跟踪。


Finally, if you inherited from BaseException instead of Exception , then obviously Exception won't catch it. 最后,如果您继承自BaseException而不是Exception ,那么显然Exception将无法捕获它。

class MyException(BaseException):
    def __init__(self, msg):
        pass

try:
    raise MyException("dsfsdf")
except Exception:
    pass

Once again, this will always fail to catch what you raised, and you'll quit with a traceback. 再次,这总是无法捕捉到你所筹集的东西,你将退出追溯。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM