18 Dec. 2009

Classes as Decorators of Methods in Python

I have had some trouble to figure out how to use a class as a decorator for a method (as opposed to a decorator for a function). Here is a script that prints some useful information about what is called when and with what parameters.

#!/usr/bin/env python
print "Classes as Decorators of Methods\n"
print "-----Parsing dec"
class dec(object):
    def __init__(self, a):
        print "----- dec init"
        print type(a)
        print "decorated method: ", a.__name__
        self.a = a
    def __get__(self, inst, cls):
        print "-----dec get"
        self._inst = inst
        self._cls = cls
        return self
    def __call__(self, p):
        print "-----dec call"
        print type(self)
        print type(self._inst)
        print type(self._cls)
        return self.a(self._inst, p.upper())

print "-----Parsing C"
class C(object):
    def __init__(self):
        self.X = "Hello"
    def run(self, p):
        print p,
        print self.X,
        return "world"

if __name__ == "__main__":
    print "-----Object creation"
    c = C()
    print "-----Object method call"
    print c.run("This is a decorator ")

This produces the following output:
Classes as Decorators of Methods

-----Parsing dec
-----Parsing C
----- dec init
type 'function'
decorated method: run
-----Object creation
-----Object method call
-----dec get
-----dec call
class '__main__.dec'
class '__main__.C'
type 'type'

In contrast: functions as decorators for functions

#!/usr/bin/env python

print "--- Parsing dec"
def dec(f):
    print "--- Run dec"
    print f.__defaults__
    def x(*args, **kwargs):
        print "--- Run x"
        print f.__name__
        print args
        print kwargs
        f(*args, **kwargs)
    return x

print "--- Parsing foo"
def foo(a, b=3):
    print "--- Run foo"
    print a, b

print "--- Calling foo"
print "--- Calling foo"
foo(2, 4)
Which outputs:
--- Parsing dec
--- Parsing foo
--- Run dec
--- Calling foo
--- Run x
--- Run foo
1 3
--- Calling foo
--- Run x
(2, 4)
--- Run foo
2 4

comments powered by Disqus