I want to, for debugging purposes, print out something pertaining to each and every line executed in a python method.
For example if there was some assignment in the line, i want to print what value was assigned for that variable, and if there was a function call, i want to print out the value returned by the function, etc.
So, for example if i were to use a decorator, applied on function/method such as :
@some_decorator
def testing() :
a = 10
b = 20
c = a + b
e = test_function()
the function testing when called, should print the following :
a = 10
b = 20
c = 30
e = some_value
Is there some way to achieve this? More fundamentally, i want to know whether i can write a code that can go through some other code line by line, check what type of an instruction it is, etc. Or maybe like we can get a dictionary for finding out all the variables in a class, can i get a dictionary like datastructure for getting every instruction in a function, which is as good a metaprogram can get.
Hence, I am particularly looking a solution using decorators, as I am curious if one can have a decorator that can go through an entire function line by line, and decorate it line by line, but any and all solutions are welcome.
Thanks in advance.
Decorators in Python are the design pattern that allows the users to add new functionalities to an existing object without the need to modify its structure. Decorators are generally called before defining a function the user wants to decorate.
__wrapped__ in Python decorators As we can see from the code of the functools module 1, when decorating an object, there is an attribute named __wrapped__ that holds the reference to the original one. So now if we use this, we can access it directly without having to resort to the old quirks.
Return values from decorated functions don't get returned by default unless the decorator allows it. In this lesson, you'll see how to get return values out of decorated functions by making a small change to the decorator.
Python allows us to implement more than one decorator to a function. It makes decorators useful for reusable building blocks as it accumulates several effects together. It is also known as nested decorators in Python.
How about something like this? Would this work for you?
Debug Context:
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))
Debug Decorator:
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
Usage
@debug_decorator
def testing() :
a = 10
b = 20
c = a + b
testing()
Output
###########################################################
#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}
###########################################################
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With