HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Function and method debugging decorator - Part 2

Submitted by: @import:stackexchange-codereview··
0
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:

  • 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 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_string


You 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_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))
    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.