将日志信息包装在上下文管理器周围,就像这样,尽管您可以轻松更改详细信息以满足您的要求:
import traceback
# This is a context manager
class LogError(object):
def __init__(self, logfile, message):
self.logfile = logfile
self.message = message
def __enter__(self):
return self
def __exit__(self, type, value, tb):
if type is None or not issubclass(type, Exception):
# Allow KeyboardInterrupt and other non-standard exception to pass through
return
self.logfile.write("%s: %r\n" % (self.message, value))
traceback.print_exception(type, value, tb, file=self.logfile)
return True # "swallow" the traceback
# This is a helper class to maintain an open file object and
# a way to provide extra information to the context manager.
class ExceptionLogger(object):
def __init__(self, filename):
self.logfile = open(filename, "wa")
def __call__(self, message):
# override function() call so that I can specify a message
return LogError(self.logfile, message)
关键部分是 __exit__ 可以返回 'True',在这种情况下异常被忽略,程序继续执行。代码还需要小心一点,因为可能会引发 KeyboardInterrupt (control-C)、SystemExit 或其他非标准异常,并且您确实希望程序在哪里停止。
您可以像这样在代码中使用上述内容:
elog = ExceptionLogger("/dev/tty")
with elog("Can I divide by 0?"):
1/0
for i in range(-4, 4):
with elog("Divisor is %d" % (i,)):
print "5/%d = %d" % (i, 5/i)
该片段给了我输出:
Can I divide by 0?: ZeroDivisionError('integer division or modulo by zero',)
Traceback (most recent call last):
File "exception_logger.py", line 24, in <module>
1/0
ZeroDivisionError: integer division or modulo by zero
5/-4 = -2
5/-3 = -2
5/-2 = -3
5/-1 = -5
Divisor is 0: ZeroDivisionError('integer division or modulo by zero',)
Traceback (most recent call last):
File "exception_logger.py", line 28, in <module>
print "5/%d = %d" % (i, 5/i)
ZeroDivisionError: integer division or modulo by zero
5/1 = 5
5/2 = 2
5/3 = 1
我认为也很容易看出如何修改代码以处理仅记录 IndexError 异常,甚至传递基本异常类型以进行捕获。