これはこれまでで最もばかげた質問かもしれませんが、例外が発生した場合にローカル変数の内部状態をキャッチできるように、関数 (できればデコレータ) の周りにラッパーを記述する方法があるかどうかを知りたいです。その関数で発生します。作成時にローカルをキャッチし、それらをピクルし、例外が発生しなかった場合はそれらを破棄し、例外が見つかった場合はそれらをファイルに書き込みます。
これはあまりにも空想的ですか、それとも誰かがこのようなことでだまされましたか?
これはこれまでで最もばかげた質問かもしれませんが、例外が発生した場合にローカル変数の内部状態をキャッチできるように、関数 (できればデコレータ) の周りにラッパーを記述する方法があるかどうかを知りたいです。その関数で発生します。作成時にローカルをキャッチし、それらをピクルし、例外が発生しなかった場合はそれらを破棄し、例外が見つかった場合はそれらをファイルに書き込みます。
これはあまりにも空想的ですか、それとも誰かがこのようなことでだまされましたか?
f_locals
traceback のフレームで変数をキャプチャできます。
import sys
import functools
def capturelocals(func):
@functools.wraps(func)
def wrapperfunc(*args, **kw):
try:
return func(*args, **kw)
except Exception:
_, _, tb = sys.exc_info()
try:
while tb.tb_next is not None:
tb = tb.tb_next # find innermost frame
locals = tb.tb_frame.f_locals
print locals
finally:
del tb # prevent leaking tracebacks
raise
return wrapperfunc
それが機能することを実証するには:
>>> @capturelocals
... def foobar():
... foo = 'bar'
... spam = 'eggs'
... raise ValueError('Bam!')
...
>>> foobar()
{'foo': 'bar', 'spam': 'eggs'}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in wrapperfunc
File "<stdin>", line 5, in foobar
ValueError: Bam!
別のオプションは、壊滅的な事態が発生した場合に保存したい変数だけを引数として関数に渡すことです。
これを行うのに役立つデコレータ:
import os
try:
import cPickle as pickle
except ImportError:
import pickle
def save_args_if_exception(pickle_folder):
def real_decorator(function):
def wrapper(*args, **kwargs):
try:
function(*args, **kwargs)
except:
print 'FAILING SAFE: Saving arguments to folder:'
print pickle_folder
for arg_position, arg in enumerate(args, start=1):
arg_fname = os.path.join(pickle_folder, str(arg_position) +
'.pickle')
print 'Saving positional argument-{}'.format(arg_position)
with open(arg_fname, mode='wb') as f:
pickle.dump(arg, f)
print 'Saving keyword arguments (kwargs)'
with open(os.path.join(pickle_folder, 'kwargs.pickle'),
mode='wb') as f:
pickle.dump(kwargs, f)
raise # re-raise original exception
return wrapper
return real_decorator
@save_args_if_exception(os.getcwd())
def important_function(first_arg, second_arg=2, **kwargs):
print 'About to raise an exception!'
raise Exception
important_function(3)
この例でsecond_arg
は、 はファイルに保存されないことに注意してください。おそらく、Python がデフォルト引数を処理する方法が原因です。状況に応じて、これは有用な動作である場合とそうでない場合があります。
参考文献: