Ramblings

March 18, 2008

Python Decorators

Filed under: cool, dev, python — michaelangela @ 8:19 am

I think I’ve written about David Mertz before. I have been learning as I read through his writings but it takes a while. There’s quite a bit that’s written for those with a much deeper understanding of python. This article is an example. I may have even commented before on my blog but I think I ‘got’ it a bit better this time. It helps to run some tests in iPython’s debugger and step through things to see how it happens at run time as well.

Charming Python: Decorators make magic easy

Listing 9. A decorator to add and remove methods

        
def flaz(self): return 'flaz' # Silly utility method
def flam(self): return 'flam' # Another silly method

def change_methods(new):
"Warning: Only decorate the __new__() method with this decorator"
if new.__name__ != '__new__':
return new # Return an unchanged method
def __new__(cls, *args, **kws):
cls.flaz = flaz
cls.flam = flam
if hasattr(cls, 'say'): del cls.say
return super(cls.__class__, cls).__new__(cls, *args, **kws)
return __new__

class Foo(object):
@change_methods
def __new__(): pass
def say(self): print "Hi me:", self

foo = Foo()
print foo.flaz() # prints: flaz
foo.say() # AttributeError: 'Foo' object has no attribute 'say'

Actually I think I did write about the decorator module before… but now it makes more sense. 🙂 One good example is the “memoize” pattern. The concept is what I would refer to as “caching”:

This decorator implements the memoize pattern, i.e. it caches
the result of a function in a dictionary, so that the next time
the function is called with the same input parameters the result is retrieved
from the cache and not recomputed.

#<_main.py>

from decorator import *

def getattr_(obj, name, default_thunk):
"Similar to .setdefault in dictionaries."
try:
return getattr(obj, name)
except AttributeError:
default = default_thunk()
setattr(obj, name, default)
return default

@decorator
def memoize(func, *args):
dic = getattr_(func, "memoize_dic", dict)
# memoize_dic is created at the first call
if args in dic:
return dic[args]
else:
result = func(*args)
dic[args] = result
return result

#</_main.py>

Here is a test of usage:

>>> @memoize
... def heavy_computation():
... time.sleep(2)
... return "done"
>>> print heavy_computation() # the first time it will take 2 seconds
done
>>> print heavy_computation() # the second time it will be instantaneous
done
Advertisements

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: