patternpythonMinor
Function and method debugging decorator - Part 2
Viewed 0 times
debuggingmethodpartfunctionanddecorator
Problem
This is a follow-up to this question.
I've refactored my previous debugging decorator, and added a couple new features, and changed a few things. Here's a complete list of things that have changed:
I'm wondering the following:
debug.py
```
from pprint import pformat
from inspect import getargspec
class Debug(object):
"""Decorator for debugging functions.
This decorator is used to debug a function, or
a class method. If this is applied to a normal
function, it will print out the arguments of
Keyword arguments:
debug -- Whether or not you want to output debug info. Generally, a global DEBUG variable is passed in here.
"""
def __init__(self, debug=True):
self.debug = debug
def __format_debug_string(self, function, *args, **kwargs):
"""Return a formatted debug string.
This is a small private helper function that will
return a string value with certain debug information.
Keyword arguments:
function -- The function to debug.
*args -- The normal arguments of the function.
**kwargs -- The keyword arguments of the function.
"""
debug_string = ""
debug_
I've refactored my previous debugging decorator, and added a couple new features, and changed a few things. Here's a complete list of things that have changed:
- There is only one decorator,
Debug, and it now supports functions, and class methods.
- Each debug message is prefixed with
[debug]to help distinguish it from normal output.
- The output now tells you what it's outputting, rather than just outputting unreadable data.
- The decorator will now output local variables names, along with argument and keyword argument names as well.
I'm wondering the following:
- Is there a way to get the values of local variables in the function, or is that just not possible?
- Is there a shorter way to get the names of local variables than
function.__code__.co_varnames?
- Is it a good idea to create an empty string, and then add to, and re-assign it to build an output string?
- Is this Python 3, and Python 2.7 compatible?
- How's my documentation?
- Is this code "pythonic"?
debug.py
```
from pprint import pformat
from inspect import getargspec
class Debug(object):
"""Decorator for debugging functions.
This decorator is used to debug a function, or
a class method. If this is applied to a normal
function, it will print out the arguments of
Keyword arguments:
debug -- Whether or not you want to output debug info. Generally, a global DEBUG variable is passed in here.
"""
def __init__(self, debug=True):
self.debug = debug
def __format_debug_string(self, function, *args, **kwargs):
"""Return a formatted debug string.
This is a small private helper function that will
return a string value with certain debug information.
Keyword arguments:
function -- The function to debug.
*args -- The normal arguments of the function.
**kwargs -- The keyword arguments of the function.
"""
debug_string = ""
debug_
Solution
You can improve the following:
If the code is executed no matter the statement, and it always goes first, move it above the condition: (and don't forget to reverse the condition)
As for this:
You can remove the
It may not look as visually stimulating, but, it's not as redundant.
Is it a good idea to create an empty string, and then add to, and re-assign it to build an output string?
If you were directly printing these then it would be a bad idea, but in this case, not really. However, I suppose you could move them to an object, or an array and return the result of a
You could even return it as an array, and print each
You've got a few too long lines, by PEP8 standard:
As for your documentation:
I'm a bit confused by that, grammatically.
Is this Python 3, and Python 2.7 compatible?
It ran fine when I tested it in Python 2.7.9 and 3.1.1
if getargspec(function).args[0] != "self":
print(self.__format_debug_string(function, *args, **kwargs))
else:
print(self.__format_debug_string(function, *args, **kwargs))
print("[debug] Parent attributes: {}".format(pformat(args[0].__dict__)))If the code is executed no matter the statement, and it always goes first, move it above the condition: (and don't forget to reverse the condition)
print(self.__format_debug_string(function, *args, **kwargs))
if getargspec(function).args[0] == "self":
print("[debug] Parent attributes: {}".format(pformat(args[0].__dict__)))As for this:
debug_string = ""
debug_string += "[debug] {}\n".format(pformat(function))
debug_string += "[debug] Passed args: {}\n".format(pformat(args))
debug_string += "[debug] Passed kwargs: {}\n".format(pformat(kwargs))
debug_string += "[debug] Locals: {}".format(pformat(function.__code__.co_varnames))
return debug_stringYou can remove the
= "" entirely:debug_string = "[debug] {}\n".format(pformat(function))
debug_string += "[debug] Passed args: {}\n".format(pformat(args))
debug_string += "[debug] Passed kwargs: {}\n".format(pformat(kwargs))
return debug_string + "[debug] Locals: {}".format(pformat(function.__code__.co_varnames))It may not look as visually stimulating, but, it's not as redundant.
Is it a good idea to create an empty string, and then add to, and re-assign it to build an output string?
If you were directly printing these then it would be a bad idea, but in this case, not really. However, I suppose you could move them to an object, or an array and return the result of a
join function.You could even return it as an array, and print each
[debug] result. Which would remove the need for the \ns at the end, and DRY up the [debug] at the beginning of the strings (put it in the loop, not altogether)You've got a few too long lines, by PEP8 standard:
debug -- Whether or not you want to output debug info. Generally, a global DEBUG variable is passed in here.
debug_string += "[debug] Locals: {}".format(pformat(function.__code__.co_varnames))
print(self.__format_debug_string(function, *args, **kwargs))
print("[debug] Parent attributes: {}".format(pformat(args[0].__dict__)))As for your documentation:
function, it will print out the arguments of
Keyword arguments:I'm a bit confused by that, grammatically.
__call__ is a more complex function (in my mind, at least) than __format_debug_string, but it has no documentation.Is this Python 3, and Python 2.7 compatible?
It ran fine when I tested it in Python 2.7.9 and 3.1.1
Code Snippets
if getargspec(function).args[0] != "self":
print(self.__format_debug_string(function, *args, **kwargs))
else:
print(self.__format_debug_string(function, *args, **kwargs))
print("[debug] Parent attributes: {}".format(pformat(args[0].__dict__)))print(self.__format_debug_string(function, *args, **kwargs))
if getargspec(function).args[0] == "self":
print("[debug] Parent attributes: {}".format(pformat(args[0].__dict__)))debug_string = ""
debug_string += "[debug] {}\n".format(pformat(function))
debug_string += "[debug] Passed args: {}\n".format(pformat(args))
debug_string += "[debug] Passed kwargs: {}\n".format(pformat(kwargs))
debug_string += "[debug] Locals: {}".format(pformat(function.__code__.co_varnames))
return debug_stringdebug_string = "[debug] {}\n".format(pformat(function))
debug_string += "[debug] Passed args: {}\n".format(pformat(args))
debug_string += "[debug] Passed kwargs: {}\n".format(pformat(kwargs))
return debug_string + "[debug] Locals: {}".format(pformat(function.__code__.co_varnames))debug -- Whether or not you want to output debug info. Generally, a global DEBUG variable is passed in here.
debug_string += "[debug] Locals: {}".format(pformat(function.__code__.co_varnames))
print(self.__format_debug_string(function, *args, **kwargs))
print("[debug] Parent attributes: {}".format(pformat(args[0].__dict__)))Context
StackExchange Code Review Q#104266, answer score: 5
Revisions (0)
No revisions yet.