A little while ago in The 2nd Monitor, me and @Phrancis were talking about Python and debugging, and the topic of function decorators came up with this message:
Ethan Bierlein: You could even build a debug decorator. Give me a sec.
So, I built a small, simple debugging decorator, which would just print out the arguments of any method it was applied to.
I decided to go a little further though, and build two separate decorators. One for regular methods, and one built specifically for class methods. Essentially, the regular method decorator takes a function, and will print out it's arguments, and keyword arguments if debug=True
. The class method decorator does the same, except it also prints out the attributes of the class it's contained in as well.
I'm wondering a couple of things though:
- Is this a "pythonic" way to debug the arguments of a function?
- Is there any additional data that should be debugged, that I missed?
- Is the extra
ClassMethodDecorator
really needed? Or is there a simpler way to support both with one decorator? - I've built this to be Python 3, and Python 2.7 compatible. Did I do this correctly?
debug.py
from pprint import pprint
class MethodDebug(object):
"""Debug a normal method.
This decorator is used for debugging a normal method,
with normal arguments, i.e, not printing out the data
of the class it's contained in.
Keyword arguments:
debug -- Whether or not you want to debug the method.
"""
def __init__(self, debug):
self.debug = debug
def __call__(self, function):
def wrapper(*args, **kwargs):
if self.debug:
pprint(args)
pprint(kwargs)
return function(*args, **kwargs)
return wrapper
class ClassMethodDebug(object):
"""Debug a class method.
This decorator is used for debugging a class method,
with normal arguments, and self. When using this
decorator, the method will print out it's arguments
and the attributes of the class it's contained in.
Keyword arguments:
debug -- Whether or not you want to debug the method.
"""
def __init__(self, debug):
self.debug = debug
def __call__(self, function):
def wrapper(function_self, *args, **kwargs):
if self.debug:
pprint(function_self.__dict__)
pprint(args)
pprint(kwargs)
return function(function_self, *args, **kwargs)
return wrapper
test.py
from debug import MethodDebug, ClassMethodDebug
@MethodDebug(debug=True)
def normal_method(a, b):
return a * b
print(normal_method(10, 10))
class TestClass(object):
def __init__(self, a, b):
self.a = a
self.b = b
@ClassMethodDebug(debug=True)
def class_method(self, c):
return self.a * self.b * c
a = TestClass(10, 10)
print(a.class_method(10))