[Python-ideas] Default arguments in Python - the return

George Sakkis george.sakkis at gmail.com
Sun May 10 22:06:53 CEST 2009


On Sun, May 10, 2009 at 1:00 PM, George Sakkis <george.sakkis at gmail.com> wrote:

> On Sun, May 10, 2009 at 12:10 PM, Arnaud Delobelle
> <arnodel at googlemail.com> wrote:
>
>> Furthemore, by removing default arguments from the language, we can let
>> people choose what semantics they want for default arguments.  I.e, if they
>> want them to be reevaluated each time, they could write the default
>> decorator as follows (it is exactly the same as the one above except for a
>> pair of parentheses that have been added on one line.
>
> Cute, but that's still a subset of what the dynamic semantics would
> provide; the evaluated thunks would have access to the previously
> defined arguments:
>
> def foo(a, b, d=(a*a+b+b)**0.5, s=1/d):
>    return (a,b,d,s)
>
> would be equivalent to
>
> missing = object()
> def foo(a, b, d=missing, s=missing):
>    if d is missing:
>        d = (a*a+b+b)**0.5
>    if s is missing:
>        s = 1/d
>    return (a,b,d,s)


Just for kicks, here's a decorator that supports dependent dynamically
computed defaults; it uses eval() to create the lambdas on the fly:

@evaldefaults('s','d')
def foo(a, b, d='(a*a+b*b)**0.5', t=0.1, s='(1+t)/(d+t)'):
    return (a,b,d,t,s)

print foo(3,4)

#=======

import inspect
import functools
# from http://code.activestate.com/recipes/551779/
from getcallargs import getcallargs

def evaldefaults(*eval_params):
    eval_params = frozenset(eval_params)
    def decorator(f):
        params,_,_,defaults = inspect.getargspec(f)
        param2default = dict(zip(params[-len(defaults):], defaults))
if defaults else {}
        param2lambda = {}
        for p in eval_params:
            argsrepr = ','.join(params[:params.index(p)])
            param2lambda[p] = eval('lambda %s: %s' % (argsrepr,
param2default[p]),
                                   f.func_globals)
        @functools.wraps(f)
        def wrapped(*args, **kwargs):
            allkwargs,missing = getcallargs(f, *args, **kwargs)
            missing_eval_params = eval_params.intersection(missing)
            f_locals = {}
            for i,param in enumerate(params):
                value = allkwargs[param]
                if param in missing_eval_params:
                    allkwargs[param] = value = param2lambda[param](**f_locals)
                f_locals[param] = value
            return f(**allkwargs)
        return wrapped
    return decorator


George



More information about the Python-ideas mailing list