lin的Decorator来记录函数的执行行

2024-09-27 23:27:16 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在编写一个需要几分钟才能运行的脚本,并希望向用户提供一些有关其进度的输出。不幸的是我太懒了。我想做的是在不记录日志的情况下编写一个函数,然后对它应用一个decorator,在执行该行之前逐步遍历函数并打印每一行。基本上我要找的是一个loggingdecorator这样:

>>> @loggingdecorator
... def myfunction():
...     foo()
...     bar()
...     baz()
>>> myfunction()
Starting myfunction
foo() ... [OK]
bar() ... [OK]
baz() ... [OK]
myfunction Done!

以下是我目前所做的尝试:

^{pr2}$

不幸的是,这会打印太多;它会跟随函数调用并逐行打印出来(实际上,这并不会打印源代码行,使用inspect的现有答案与trace函数中frame对象上的内容结合起来就可以了),但我对logging_tracer的用法有点困惑,除非所讨论的函数是实际修饰的。在


Tags: 函数用户脚本foodef记录bar情况
3条回答

下面是一个丑陋的例子,如果只有一个缩进级别:

import inspect


def myDec(func):
    temp = list(inspect.getsourcelines(func)[0])

    temp.append('    print("{} Done!")\n'.format(func.__name__))
    for index in range(len(temp)-2, 0, -1):
        temp.insert(index+1, "    print('''{}...[OK]''')\n".format(temp[index].strip().rstrip("\n")))
    temp.insert(1, '    print("Starting {}")\n'.format(func.__name__))
    temp = "".join(temp)
    exec(temp)
    return locals()[func.__name__]

def foo():
    a = 4+5
    list_int = range(100)


foo = myDec(foo)
foo()

不过真的很难看。。。在

你可以这样做:

>>> class loggingdecorator:
...     def __init__(self, func):
...             self.func = func
...     def __call__(self):
...             print "Entering", self.func.__name__
...             self.func()
...             print "Exited", self.func.__name__
...

然后使用每个函数:

^{pr2}$

找到了来自this page的示例

这就是我的想法。@Corley Brigman的评论让我有了正确的开始。这有点骇人听闻,sys.gettrace/settrace被很快地记录为“CPython实现细节”,因此不应期望此解决方案在其他实现中起作用。这就是说,看起来效果不错。cpython中的跟踪功能没有提供任何“line finished executing”的通知,因此我的问题中的[ok]没有任何意义。在

修复递归跟踪问题只是一个简单的问题,即保留已修饰函数的缓存,然后只在被跟踪的帧来自已修饰的函数时生成输出。在

import inspect
import sys


def logging_tracer(frame, event, arg):
    lines, firstline = inspect.getsourcelines(frame)

    def local_tracer(local_frame, event, arg):
        if event == 'line' and frame is local_frame:
            print event, frame.f_lineno,'\t', lines[frame.f_lineno - firstline]
            #print event, lines[frame.f_lineno - firstline]
            #print frame.f_code.co_name, frame.f_lineno, event, arg

    if frame.f_code in LOG_THESE_FUNCTIONS:
        print event, frame.f_lineno,'\t', lines[frame.f_lineno - firstline + (event == 'call')]
        #print frame.f_code.co_name, event, arg
        return local_tracer
    else:
        return None


LOG_THESE_FUNCTIONS = set()


def loggingdecorator(func):
    LOG_THESE_FUNCTIONS.add(func.func_code)

    def _wrapper():
        old_trace_function = sys.gettrace()
        sys.settrace(logging_tracer)
        try:
            result = func()
        except:
            raise
        else:
            return result
        finally:
            sys.settrace(old_trace_function)
    return _wrapper

相关问题 更多 >

    热门问题