functions, optional parameters

Ian Kelly ian.g.kelly at gmail.com
Sat May 9 12:57:01 EDT 2015


On Fri, May 8, 2015 at 9:50 AM, Michael Welle <mwe012008 at gmx.net> wrote:
>
> Steven D'Aprano <steve+comp.lang.python at pearwood.info> writes:
>>
>> If your language uses late binding, it is very inconvenient to get early
>> binding when you want it. But if your language uses early binding, it is
>> very simple to get late binding when you want it: just put the code you
>> want to run inside the body of the function:
> And you have to do it all the time again and again. I can't provide hard
> numbers, but I think usually I want late binding.

You could perhaps write a decorator to evaluate your defaults at call
time. This one relies on inspect.signature, so it requires Python 3.3
or newer:

import inspect
from functools import wraps

def late_defaults(**defaults):
    def decorator(f):
        sig = inspect.signature(f)
        @wraps(f)
        def wrapped(*args, **kwargs):
            bound_args = sig.bind_partial(*args, **kwargs)
            for name, get_value in defaults.items():
                if name not in bound_args.arguments:
                    bound_args.arguments[name] = get_value()
            return f(*bound_args.args, **bound_args.kwargs)
        return wrapped
    return decorator

@late_defaults(b=lambda: x+1, c=lambda: y*2)
def f(a, b, c=None):
    print(a, b, c)

x = 14
y = 37
f(10)
x = 30
y = 19
f(10)
f(10, 11)
f(10, 11, c=12)

Output:

10 15 74
10 31 38
10 11 38
10 11 12

For documentation purposes I suggest using default values of None in
the function spec to indicate that the arguments are optional, and
elaborating on the actual defaults in the docstring. Alternatively you
could put the lambdas in the the actual function spec and then just
tell the decorator which ones to apply if not supplied, but that would
result in less readable pydoc.



More information about the Python-list mailing list