在定义函数时如何使用try...except?

4 投票
4 回答
1293 浏览
提问于 2025-04-15 21:07

我发现自己对一个问题感到困惑,那就是在什么情况下我不需要使用 try..except。在过去的几天里,我在几乎每个定义的函数中都用了它,我觉得这可能不是个好习惯。例如:

class mongodb(object):

    def getRecords(self,tname,conditions=''):
        try:
            col = eval("self.db.%s" %tname)
            recs = col.find(condition)
            return recs
        except Exception,e:
            #here make some error log with e.message

我想的是,异常可能会在任何地方发生,所以我必须使用 try 来捕捉它们。 我的问题是,在定义函数时,随便使用它是否是个好习惯?如果不是,那有没有什么原则可以遵循?希望能得到帮助!

祝好

4 个回答

4

你需要在几个目标之间找到一个平衡:

  1. 一个应用程序应该尽可能自己恢复错误。

  2. 一个应用程序应该详细报告所有无法恢复的错误,以便找到问题的根源。

  3. 错误可能在任何地方发生,但你不想让你的代码到处都是处理错误的代码。

  4. 应用程序不应该崩溃。

为了处理第3个目标,你可以使用一个叫做异常钩子的东西。所有未处理的异常会导致当前的操作中止。你应该在最高层捕获这些异常,回滚操作(这样数据库就不会变得不一致),然后要么重新抛出这些异常,要么吞掉它们(这样应用程序就不会崩溃)。你可以使用装饰器来实现这一点。这可以解决第4和第1个目标。

解决第2个目标的办法是经验。随着时间的推移,你会学到解决问题需要哪些信息。困难的部分是当错误发生时,仍然能够获取这些信息。一个解决方案是在低级方法中添加调试日志调用。

另一个解决方案是为每个线程创建一个字典,用来存储一些信息,并在发生错误时将其输出。

5

这样做(非常宽泛地捕获所有可能的异常)确实被认为是不好的做法。这样会掩盖异常的真正原因。

只捕获那些你明确知道的异常类型(也就是你预期会发生的,并且你能够妥善处理的)。让其他那些(意外的异常)自然抛出。

你可以通过重写 sys.excepthook 来全局记录这些(未捕获的)异常:

import sys
import traceback
# ...

def my_uncaught_exception_hook(exc_type, exc_value, exc_traceback):
    msg_exc = "".join( \
              traceback.format_exception(exc_type, exc_value, exc_traceback) )
    # ... log here...

sys.excepthook = my_uncaught_exception_hook # our uncaught exception hook
5

这样做可能不是最好的选择。异常的主要目的就是让你可以在抛出异常的地方以外的地方去处理它。最好是在你有足够信息的地方来处理这些异常,这通常取决于具体的应用和上下文。

例如,下面的代码可能会抛出一个IOError("[Errno 2] 没有这样的文件或目录"):

def read_data(filename):
    return open(filename).read()

在那个函数里,你没有足够的信息去处理这个异常,但在你实际使用这个函数的地方,如果出现这样的异常,你可以选择尝试不同的文件名,或者向用户显示错误信息,或者做其他事情:

try:
    data = read_data('data-file.txt')
except IOError:
    data = read_data('another-data-file.txt')
    # or
    show_error_message("Data file was not found.")
    # or something else

撰写回答