要件に合わせて詳細を簡単に変更できますが、このようにログ情報をコンテキストマネージャーにラップします。
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例外のみのログを処理するように、またはキャッチするために基本例外タイプを渡すようにコードを変更する方法も簡単に理解できると思います。