@Decorators and Property() with Python
What are they
Decorators are syntatic sugar to wrap functions
def doHardWork(): print 'Do hard work' def myDecorator(function): def wrapper(): print 'Wake up' function() print 'Go to sleep' return wrapper doHardWork = myDecorator(doHardWork) doHardWork()
so that instead of
doHardWork = myDecorator(doHardWork) doHardWork()
we can write
@myDecorator def doHardWork
which is much prettier.
What are they good for
Decorators are convenient for factoring out common prologue, epilogue, and/or exception-handling code in similar functions. Besides the obvious @login_required
, other nice decorators are:
Timing a function
def timing_function(some_function): def wrapper(): t1 = time.time() some_function() t2 = time.time() return "str((t2-t1)) + "\n" return wrapper
Debugging functions
def debug(fn): def wrapper(*args): result = fn(*args) print '{0}{1} : {2}'.format(fn.__name__, args, result) return result return wrapper @debug def doHardWork(someArg): if type(someArg) is int: return 'int' elif type(someArg) is str: return 'str' else: return 'other' doHardWork([])
Interesting discussion here: http://www.quora.com/What-are-common-uses-of-Python-decorators
Property() and decorators
Property()
is a built in wrapper function that attaches some code to the member attribute access. It’s the Python way to deal without C++ getters/setters.
In this example I create a new member variable title
, and I attach the two custom functions to get
and set
for that member. Throughout the class, code>_title is underscored to mean that it shouldn’t be accessed from outside the class.
class Book(): def __init__(self): self._title = '' def get_title(self): if self._title == '': return 'title not set' else: return self._title def set_title(self, title): if len(title) < 2: raise ValueError('Too short') self._title = title return self._title # property() attaches some code to the member # attribute access, in this case 'title'. # # the property() signature is: # property(fget=None, fset=None, fdel=None, doc=None) title = property(get_title, set_title) b = Book() print(b.title) b.title = 'moby dick' print(b.title)
The whole example just screams for decorators :)
Also note that in Python, a method is a function that is stored as a class attribute, so it makes perfect sense that title
here is a method whereas in the previous example it was an attribute.
class Book(): def __init__(self): self._title = '' # this is the same as # title = property(title) @property def title(self): if self._title == '': return 'title not set' else: return self._title # returns a new property that inherits everything from # the old title(), plus it adds a setter @title.setter def title(self, title): if len(title) < 2: raise ValueError('Too short') self._title = title return self._title b = Book() print(b.title) b.title = 'moby dick' print(b.title)