الحصول على وسيطات استدعاء الوظيفة الأخيرة من Traceback؟

StackOverflow https://stackoverflow.com/questions/1650713

سؤال

هل يمكنني الحصول على معلمات آخر وظيفة تسمى في 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 ؛ هذا ليس مهمًا لمكالمة تصحيح أخطاء ، ولكن يمكن أن تكون مشكلة في حالات أخرى).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top