[Python-Dev] Re: PEP 318: Let's propose some useful built-in
decorators
Isaac Freeman
ishnigarrab at earthlink.net
Sat Apr 3 19:00:38 EST 2004
Here are a few ideas (including a meta-decoration! :)
Of course, I'm biased to first-before-colon style. ;)
--- decorators.py ---
import inspect
class decorator:
""" An obscenely gratuitous example of decorator usage. Meta-decoration?
"One mans use is another man's abuse"
"""
class decoration:
""" The object that represents the decoration itself. """
def __init__(decor, func, **state):
self.func = func
self.state = {'func': func.__name__}
def __call__(self, *args, **kwds):
""" Called when the function that is decorated by this
decoration is
called. (whew)
"""
self.state.update(inspect.getargvalues(sys._getframe(1))[3])
# better way?
return self.decor(self.func, self.state, *args, **kwds)
def options(self, opts=None, **kwd_opts):
self.state.update(opts or kwd_opts)
return self
def __init__(self, decor):
self.decor = decor
def __call__(self, func):
""" Called when the decorator is called to decorate a desired
function. """
init = self.init
init.update(kwds)
return self.decoration(decor, func)
def fromstate(cls, state=None, **kwd_state) [classmethod]:
""" Make a decoration with a specified initial state """
return lambda fn: cls(fn, state or kwd_state)
# or...
# Smaller, but can be confusing. (But I guess the whole
# meta-function-generator thing is to begin with!)
def decorator2(decor=None, **state):
""" Decoration factory. """
def decoration2(func=None, **opts):
""" Decorating function wrapper. """
state.update(opts)
state['func'] = func.__name__
def callit(*args, **kwds):
""" Function replacement. """
state.update(inspect.getargvalues(sys._getframe(1))[3]) #
better way?
decor(func, state, *args, **kwds)
if func:
return callit
else:
return lambda fn: decoration2(fn, **opts)
if decor:
return decoration
else:
return lambda dec: decorator2(dec, state)
def memoized(func, state, *args, **kwds) [decorator]:
""" Function wrapper to cache the results of previously
evaluated arguments.
"""
items = kwds.items
items.sort()
key = (args, tuple(items)) # hope everything is hashable!
return ( state.get(key)
or state.setdefault(key, func(*args, **kwds)) )
def memoized2(func, state, *args, **kwds) [decorator2]:
key = (args, tuple(kwds.items()))
return ( state.get(key)
or state.setdefault(key, func(*args, **kwds)) )
import sys, time
def logged(func, state, *args, **kwds) [decorator.fromstate(
output=sys.stdout.write,
prefix='%(func)s: ')]:
""" Usage for default formatting and output:
def func(*args) [logged]:
pass
Usage for custom formatting and output:
def func(a, b) [logged.options(output=output_func,
prefix="%(func)s %(a)s %(b)i")]:
pass
String replacements include 'func' which is the function's name,
as well
as all arguments to the function such that "%(a)s" would become
the value
of the argument named 'a'.
"""
p = '[%s] %s' % (time.time(), state['prefix'] % state)
state['output'](p)
def logged2(func, state, *args, **kwds) [decorator2(
output=sys.stdout.write,
prefix='%(func)s: ')]:
""" Usage for default formatting and output:
def func(*args) [logged2]:
pass
Usage for custom formatting and output:
def func(a, b) [logged2(output=output_func,
prefix="%(func)s %(a)s %(b)i")]:
pass
String replacements include 'func' which is the function's name,
as well
as all arguments to the function such that "%(a)s" would become
the value
of the argument named 'a'.
"""
p = '[%s] %s' % (time.time(), state['prefix'] % state)
state['output'](p)
# demo function
def factorial(n) [memoized,
logged.options(output=sys.stdout.write,
prefix='factorial for %(n)s: ')]:
""" Computes the factorial of n """
print "fact(%i)" % n
if n == 1:
return 1
else:
return n * fact(n - 1) # make tail_recursive decorator(?)
def factorial2(n) [memoized,
logged2(output=sys.stdout.write,
prefix='factorial for %(s): ')]:
""" Computes the factorial of n """
print "fact(%i)" % n
if n == 1:
return 1
else:
return n * fact(n - 1)
More information about the Python-Dev
mailing list