Skip to content

Instantly share code, notes, and snippets.

@slowli slowli/decorators.py
Created Jun 22, 2015

Embed
What would you like to do?
A little demonstration of decorators in Python
#!/usr/bin/python
'''
A little demonstration of decorators in Python.
'''
import sys
def noargs(decorator):
''' Decorator enabling use of no-args form for parametric decorators. '''
def noarg_fn(*args, **kvargs):
if len(args) == 1 and callable(args[0]) and len(kvargs) == 0:
# Decorator with no args is used,
# args[0] is a transformed function
return decorator()(args[0])
else:
return decorator(*args, **kvargs)
return noarg_fn
@noargs
def log(prefix='LOG>>> ', fh=sys.stderr):
''' Decorator logging function calls. '''
def decorate(fn):
def logged_fn(*args):
result = fn(*args)
fh.write(prefix + '{0}{1} = {2}\n'.format(
fn.__name__, args, result))
return result
return logged_fn
return decorate
@noargs
def cached(mapargs = lambda *args: args):
''' Caching decorator.
mapargs argument allows cashing functions with non-hashable arguments.
It can also be used to implement custom comparison between argument tuples. '''
def decorate(fn):
cache = dict()
def cached_fn(*args):
mapped_args = mapargs(*args)
if not mapped_args in cache:
cache[mapped_args] = fn(*args)
return cache[mapped_args]
return cached_fn
return decorate
@log
def lplus(x, y): return x + y
# equivalent to
# @log()
# def lplus(...): ...
@log('! ')
def lminus(x, y): return x - y
# equivalent to
# @log(prefix = '! ')
# def lminus(...): ...
class RecurrentSum(object):
'''
The common class for sequences described by the recurrent relationship
F(i) = F(i - 1) + F(i - 2) + ... + F(i - k), k >= 2;
F(1) = F(2) = ... = F(k) = 1.
'''
def __init__(self, count):
self.count = count
# Decorators work with special methods (indexing, in this case).
@cached
def __getitem__(self, n):
if n < self.count: return 1
sum = 0
for i in range(max(0, n - self.count), n):
sum += self[i]
return sum
def __str__(self):
return 'RecurrentSum({0})'.format(self.count)
def __repr__(self):
return self.__str__()
def test_decorators():
lplus(1, 5)
lplus([2], [6, 9])
lplus('abc', 'def')
lminus(3, 6)
lminus(set([2, 3, 5, 7]), set([0, 1, 2, 3]))
fib = RecurrentSum(2) # Fibonacci numbers
trib = RecurrentSum(3) # Tribonacci numbers
print 'Fibonacci numbers:'
print ' '.join([ str(fib[i]) for i in range(20) ])
print 'Tribonacci numbers:'
print ' '.join([ str(trib[i]) for i in range(20) ])
if __name__ == '__main__':
test_decorators()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.