الحصول على وسيطات استدعاء الوظيفة الأخيرة من Traceback؟
-
22-07-2019 - |
سؤال
هل يمكنني الحصول على معلمات آخر وظيفة تسمى في Traceback؟ كيف؟
أرغب في إنشاء صياد للأخطاء القياسية لإنشاء رمز قابل للقراءة ، ولكن تقديم معلومات مفصلة للمستخدم.
في المثال التالي ، أريد get_params أن يعيد لي مجموعة من المعلمات المقدمة إلى OS.Chown. فحص inspect
الوحدة التي نصحها أليكس مارتيلي ، لم أتمكن من العثور على ذلك.
def catch_errors(fn):
def decorator(*args, **kwargs):
try:
return fn(*args, **kwargs)
except (IOError, OSError):
msg = sys.exc_info()[2].tb_frame.f_locals['error_message']
quit(msg.format(SEQUENCE_OF_PARAMETERS_OF_THE_LAST_FUNCTION_CALLED)\
+ '\nError #{0[0]}: {0[1]}'.format(sys.exc_info()[1].args), 1)
return decorator
@catch_errors
def do_your_job():
error_message = 'Can\'t change folder ownership \'{0}\' (uid:{1}, gid:{2})'
os.chown('/root', 1000, 1000) # note that params aren't named vars.
if __name == '__main__' and os.getenv('USERNAME') != 'root':
do_your_job()
(بفضل جيم روبرت للديكور)
المحلول
المشكلة في استخدام ديكور لما تحاول تحقيقه هي أن الإطار يحصل معالج الاستثناء هو do_your_job()
مخاط os.listdir()
س، os.makedirs()
S أو os.chown()
س. لذا فإن المعلومات التي ستتم طباعتها هي الحجج do_your_job()
. من أجل الحصول على السلوك الذي أعتقد أنك تنوي ، سيتعين عليك تزيين جميع وظائف المكتبة التي تتصل بها.
نصائح أخرى
لمهام التفتيش هذه ، فكر دائمًا أولاً في الوحدة النمطية inspect
في المكتبة القياسية. هنا، inccent.getargvalues يمنحك قيم الوسيطة المعطاة إطارًا ، و inccent.getInnerframes يمنحك إطارات الاهتمام من كائن Traceback.
فيما يلي مثال على هذه الوظيفة وبعض المشكلات التي لا يمكنك الالتفاف عليها:
import sys
def get_params(tb):
while tb.tb_next:
tb = tb.tb_next
frame = tb.tb_frame
code = frame.f_code
argcount = code.co_argcount
if code.co_flags & 4: # *args
argcount += 1
if code.co_flags & 8: # **kwargs
argcount += 1
names = code.co_varnames[:argcount]
params = {}
for name in names:
params[name] = frame.f_locals.get(name, '<deleted>')
return params
def f(a, b=2, c=3, *d, **e):
del c
c = 4
e['g'] = 6
assert False
try:
f(1, f=5)
except:
print get_params(sys.exc_info()[2])
الإخراج هو:
{'a': 1, 'c': 4, 'b': 2, 'e': {'g': 6, 'f': 5}, 'd': ()}
لم أستخدم inspect.getinnerframes()
لإظهار طريقة أخرى للحصول على إطار مطلوب. على الرغم من أنه يبسط قليلاً ، إلا أنه يقوم أيضًا ببعض الأعمال الإضافية غير المطلوبة بالنسبة لك بينما تكون بطيئة نسبيًا (inspect.getinnerframes()
يقرأ الملف المصدر لكل وحدة في Traceback ؛ هذا ليس مهمًا لمكالمة تصحيح أخطاء ، ولكن يمكن أن تكون مشكلة في حالات أخرى).