关于调试:Python Decorator用于打印函数执行的每一行

Python Decorator for printing every line executed by a function

我想,为了调试目的,打印出与python方法中执行的每一行有关的内容。

例如,如果行中有一些赋值,我想打印为该变量赋值的值,如果有函数调用,我想打印出函数返回的值等。

所以,例如,如果我使用装饰器,应用于函数/方法,如:

1
2
3
4
5
6
@some_decorator
def testing() :
    a = 10
    b = 20
    c = a + b
    e = test_function()

调用函数测试时,应打印以下内容:

1
2
3
4
a = 10
b = 20  
c = 30
e = some_value

有没有办法实现这个目标?更基本的是,我想知道我是否可以编写一个可以逐行查看其他代码的代码,检查它是什么类型的指令,等等。或者就像我们可以得到一个字典来查找所有变量一个类,我可以得到像数据结构这样的字典来获取函数中的每个指令,这是一个好的元程序可以得到的。

因此,我特别期待使用装饰器的解决方案,因为我很好奇是否可以有一个装饰器可以逐行遍历整个功能,并逐行装饰,
但欢迎任何和所有解决方案。

提前致谢。


这样的事怎么样? 这对你有用吗?

调试上下文:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import sys

class debug_context():
   """ Debug context to trace any function calls inside the context"""

    def __init__(self, name):
        self.name = name

    def __enter__(self):
        print('Entering Debug Decorated func')
        # Set the trace function to the trace_calls function
        # So all events are now traced
        sys.settrace(self.trace_calls)

    def __exit__(self, *args, **kwargs):
        # Stop tracing all events
        sys.settrace = None

    def trace_calls(self, frame, event, arg):
        # We want to only trace our call to the decorated function
        if event != 'call':
            return
        elif frame.f_code.co_name != self.name:
            return
        # return the trace function to use when you go into that
        # function call
        return self.trace_lines

    def trace_lines(self, frame, event, arg):
        # If you want to print local variables each line
        # keep the check for the event 'line'
        # If you want to print local variables only on return
        # check only for the 'return' event
        if event not in ['line', 'return']:
            return
        co = frame.f_code
        func_name = co.co_name
        line_no = frame.f_lineno
        filename = co.co_filename
        local_vars = frame.f_locals
        print ('  {0} {1} {2} locals: {3}'.format(func_name,
                                                  event,
                                                  line_no,
                                                  local_vars))

调试装饰器:

1
2
3
4
5
6
7
def debug_decorator(func):
   """ Debug decorator to call the function within the debug context"""
    def decorated_func(*args, **kwargs):
        with debug_context(func.__name__):
            return_value = func(*args, **kwargs)
        return return_value
    return decorated_func

用法

1
2
3
4
5
6
7
@debug_decorator
def testing() :
    a = 10
    b = 20
    c = a + b

testing()

产量

1
2
3
4
5
6
7
8
###########################################################
#output:
#   Entering Debug Decorated func
#     testing line 44 locals: {}
#     testing line 45 locals: {'a': 10}
#     testing line 46 locals: {'a': 10, 'b': 20}
#     testing return 46 locals: {'a': 10, 'b': 20, 'c': 30}
###########################################################