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
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)
    
recipes/Python/440702_Reusing_default/recipe-440702.py