text: import inspect
  import itertools as it
  from collections import deque
  
  __all__ = ['defaultsfrom']
  
  #======= demos ===============================================================
  
  def demo_func():
      '''Reuse function default values.'''
  
      def genericsort(iterable, cmp=None, key=None, reverse=False):
          raise NotImplementedError()
  
      @defaultsfrom(genericsort)
      def timsort(iterable, cmp, key, reverse):
          return sorted(iterable, cmp, key, reverse)
  
      s = ['hello', 'WORLD']
      timsort(s)
      timsort(s, key=str.lower)
  
  
  def demo_class():
      '''Reuse method default values.'''
  
      import logging
      class GenericLogger(object):
          def __init__(self, name, level=logging.WARNING, handlers=(), 
                       filters=()):
              self._logger = logging.getLogger(name)
              self._logger.setLevel(level)
              for h in handlers: self._logger.addHandler(h)
              for f in filters: self._logger.addFilter(f)
  
  
      class FancyLogger(GenericLogger):
  
          @defaultsfrom(GenericLogger)
          def __init__(self, name, level, handlers, filters, bells=None,
                       whistles=None, debug=False):
              super(FancyLogger,self).__init__(name, level, handlers, filters)
              for attr in 'bells', 'whistles', 'debug':
                  setattr(self, '_'+attr, eval(attr))
  
      mylog = FancyLogger('demo', filters=[logging.Filter()], debug=True)
  
  
  #======= defaultsfrom ========================================================
  
  def defaultsfrom(funcOrClass):
      '''Return a decorator d so that d(func) updates func's default arguments.
  
      If funcOrClass is a function (or method) 'foo', its default arguments are
      'inherited' by any function 'bar' decorated by the returned decorator:
  
      >>> def foo(a, x=0, y=''): pass
      >>> @defaultsfrom(foo)
      ... def bar(a, b, y, x, z=None): return a,b,y,x,z
      >>> bar(1,2,3,4,5)
      (1, 2, 3, 4, 5)
      >>> bar(1,2,3,4)
      (1, 2, 3, 4, None)
      >>> bar(1,2,3)
      (1, 2, 3, 0, None)
      >>> bar(1,2)
      (1, 2, '', 0, None)
  
      Any default arguments redefined by 'bar' are not inherited by 'foo':
      >>> @defaultsfrom(foo)
      ... def zong(a, x, y=-1): # y redefined
      ...     return a,x,y
      >>> zong(2)
      (2, 0, -1)
  
      Default arguments (inherited or not) cannot precede non-default ones:
      >>> @defaultsfrom(foo)
      ... def zap(a, x, b, y): # b is not a default arg; x cannot be inherited
      ...     return a,x,b,y
      Traceback (most recent call last):
          ...
      TypeError: ...
  
      If funcOrClass is a class, its method with the same name with the
      decorated function is handled as above:
      >>> class Base(object):
      ...    def __init__(self, a, b=0, c=None): pass
      >>> class Derived(Base):
      ...    @defaultsfrom(Base)  # equivalent to Base.__init__
      ...    def __init__(self, a, b, c): print (a,b,c)
      >>> d = Derived(1)
      (1, 0, None)
      '''
  
      def decorator(newfunc):
          if inspect.isclass(funcOrClass):
              func = getattr(funcOrClass, newfunc.__name__)
          else:
              func = funcOrClass
          args,_,_,defaults = inspect.getargspec(func)
          # map each default argument of func to its value
          arg2default = dict(zip(args[-len(defaults):],defaults))
          newargs,_,_,newdefaults = inspect.getargspec(newfunc)
          if newdefaults is None: newdefaults = ()
          nondefaults = newargs[:len(newargs)-len(newdefaults)]
          # starting from the last non-default argument towards the first, as
          # long as the non-defaults of newfunc are default in func, make them
          # default in newfunc too
          iter_nondefaults = reversed(nondefaults)
          newdefaults = deque(newdefaults)
          for arg in it.takewhile(arg2default.__contains__, iter_nondefaults):
              newdefaults.appendleft(arg2default[arg])
          # all inherited defaults should be placed together; no gaps allowed
          for arg in it.ifilter(arg2default.__contains__, iter_nondefaults):
              raise TypeError('%s cannot inherit the default arguments of '
                              '%s' % (newfunc, func))
          newfunc.func_defaults = tuple(newdefaults)
          return newfunc
      return decorator
  
  
  if __name__ == '__main__':
      import doctest
      doctest.testmod(optionflags=doctest.ELLIPSIS)
      demo_func()
      demo_class()
  