Differences between revisions 16 and 17
Revision 16 as of 2004-10-01 02:56:23
Size: 5639
Editor: BrettCannon
Comment:
Revision 17 as of 2004-11-28 07:59:54
Size: 5646
Editor: 81-188-17-86
Comment: Added 'return' in dumpArgs decorator when calling the decorated function
Deletions are marked like this. Additions are marked like this.
Line 225: Line 225:
        func(*args,**kwargs)         return func(*args,**kwargs)

This page is meant to be a central repository of decorator code pieces, whether useful or not <wink>. It is NOT a page to discuss decorator syntax!

Feel free to add your suggestions (please use the current decorator syntax @dec)!

Memoize

Here's a memoizing class.

inline:memoize.py

Pseudo-currying

   1 class curried(object):
   2   """
   3   Decorator that returns a function that keeps returning functions
   4   until all arguments are supplied; then the original function is
   5   evaluated.
   6   """
   7 
   8   def __init__(self, func, *a):
   9     self.func = func
  10     self.args = a
  11   def __call__(self, *a):
  12     args = self.args + a
  13     if len(args) < self.func.func_code.co_argcount:
  14       return curried(self.func, *args)
  15     else:
  16       return self.func(*args)
  17 
  18 
  19 @curried
  20 def add(a, b):
  21     return a+b
  22 
  23 add1 = add(1)
  24 
  25 print add1(2)

Controllable DIY debug

(Other hooks could be similarly added. Docstrings and exceptions are left out for simplicity of demonstration.)

   1 import sys, sets
   2 
   3 WHAT_TO_DEBUG = sets.Set(['io', 'core'])  # change to what you need
   4 
   5 class deBug:
   6     """ Decorator which helps to control what aspects of a program to debug
   7     on per-function basis. Aspects are provided as list of arguments. 
   8     It DOESN'T slowdown functions which aren't supposed to be debugged.
   9     """
  10     def __init__(self, aspects=None):
  11         self.aspects = sets.Set(aspects)
  12 
  13     def __call__(self, f):
  14         if self.aspects & WHAT_TO_DEBUG:
  15             def newf(*args, **kwds):
  16                 print >> sys.stderr, f.func_name, args, kwds
  17                 f_result = f(*args, **kwds)
  18                 print >> sys.stderr, f.func_name, "returned", f_result
  19                 return f_result
  20             newf.__doc__ = f.__doc__
  21             return newf
  22         else:
  23             return f
  24 
  25 @deBug(['io'])
  26 def prn(x):
  27     print x
  28 
  29 @deBug(['core'])
  30 def mult(x, y):
  31     return x * y
  32 
  33 prn(mult(2,2))

Easy adding methods to a class instance

Credits to John Roth.

   1 class Foo:
   2     def __init__(self):
   3         self.x = 42
   4 
   5 foo = Foo()
   6 
   7 def addto(instance):
   8     def decorator(f):
   9         import new
  10         f = new.instancemethod(f, instance, instance.__class__)
  11         setattr(instance, f.func_name, f)
  12         return f
  13     return decorator
  14 
  15 @addto(foo)
  16 def print_x(self):
  17     print self.x
  18 
  19 # foo.print_x() would print "42"

Counting function calls

   1 class countcalls(object):
   2    "Decorator that keeps track of the number of times a function is called."
   3    
   4    __instances = {}
   5    
   6    def __init__(self, f):
   7       self.__f = f
   8       self.__numCalls = 0
   9       countcalls.__instances[f] = self
  10       
  11    def __call__(self, *args, **kwargs):
  12       self.__numCalls += 1
  13       return self.__f(*args, **kwargs)
  14       
  15    @staticmethod
  16    def count(f):
  17       "Return the number of times the function f was called."
  18       return countcalls.__instances[f].__numCalls
  19       
  20    @staticmethod
  21    def counts():
  22       "Return a dict of {function: # of calls} for all registered functions."
  23       return dict([(f, countcalls.count(f)) for f in countcalls.__instances])

Creating Well-Behaved Decorators

   1 def simple_decorator(decorator):
   2     """This decorator can be used to turn simple functions
   3     into well-behaved decorators, so long as the decorators
   4     are fairly simple. If a decorator expects a function and
   5     returns a function (no descriptors), and if it doesn't
   6     modify function attributes or docstring, then it is 
   7     eligible to use this. Simply apply @simple_decorator to
   8     your decorator and it will automatically preserve the 
   9     docstring and function attributes of functions to which
  10     it is applied."""
  11     def new_decorator(f):
  12         g = decorator(f)
  13         g.__name__ = f.__name__
  14         g.__doc__ = f.__doc__
  15         g.__dict__.update(f.__dict__)
  16         return g
  17     # Now a few lines needed to make simple_decorator itself
  18     # be a well-behaved decorator.
  19     new_decorator.__name__ = decorator.__name__
  20     new_decorator.__doc__ = decorator.__doc__
  21     new_decorator.__dict__.update(decorator.__dict__)
  22     return new_decorator
  23 
  24 #
  25 # Sample Use:
  26 #
  27 @simple_decorator
  28 def mySimpleLoggingDecorator(f):
  29     print 'calling %s' % f.__name__
  30 
  31 @mySimpleLoggingDecorator
  32 def double(x):
  33     "Doubles a number"
  34     return 2*x
  35 
  36 assert(double.__name__ == 'double')
  37 assert(double.__doc__ == 'Doubles a number')

Enable/Disable Decorators

   1 def unchanged(func):
   2     "This decorator doesn't add any behavior"
   3     return func
   4 
   5 def disabled(func):
   6     "This decorator disables the provided function, and does nothing"
   7     def emptyFunc(*args,**kargs):
   8         pass
   9     return emptyFunc
  10 
  11 # define this as equivalent to unchanged, for nice symmetry with disabled
  12 enabled = unchanged
  13 
  14 #
  15 # Sample use
  16 #
  17 
  18 globalEnableFlag = int(True)
  19 
  20 @(disabled, enabled)[globalEnableFlag]
  21 def specialFunctionFoo():
  22     print "function was enabled"

Easy Dump of Function Arguments

   1 def dumpArgs(func):
   2     "This decorator dumps out the arguments passed to a function before calling it"
   3     argnames = func.func_code.co_varnames[:func.func_code.co_argcount]
   4     fname = func.func_name
   5     def echoFunc(*args,**kwargs):
   6         print fname,":", zip(argnames,args)
   7         return func(*args,**kwargs)
   8     return echoFunc
   9     
  10 @dumpArgs
  11 def f1(a,b,c):
  12     print a+b+c
  13     
  14 f1(1,2,3)

PythonDecoratorLibrary (last edited 2017-07-04 09:44:35 by mjpieters)

Unable to edit the page? See the FrontPage for instructions.