[Python-ideas] Idea: Deferred Default Arguments?
Peter O'Connor
peter.ed.oconnor at gmail.com
Fri Jul 20 10:43:56 EDT 2018
Ah, right, the fix_it(fcn) is a nice idea. It might also be a good idea,
if we're making an external library anyway, to have a "deferred" object to
avoid overloading "None" (which may mean something else than "differ
argument"). I implemented the decorator here
<https://github.com/petered/peters_example_code/blob/master/peters_example_code/deferral.py>,
and it can be used as:
from deferral import deferrable_args, deferred
@deferrable_args
def subfunction_1(a=2, b=3, c=4):
return a+b*c
@deferrable_args
def subfunction_2(d=5, e=6, f=7):
return d*e+f
def main_function(a=deferred, b=deferred, c=deferred, d=deferred,
e=deferred, f=deferred):
return subfunction_1(a=a, b=b, c=c) + subfunction_2(d=d, e=e, f=f)
assert main_function() == (2+3*4)+(5*6+7)
assert main_function(a=8) == (8+3*4)+(5*6+7)
I still think it would be nice to have this as a built-in python feature,
for a few reasons:
- When using non-differable functions (say in other codebases), we have to
do a bunch of "func = deferrable_args(func)" at the top of the module (or
we can just do them at runtime, but then we're doing inspection every time,
which is probably slow).
- It adds a layer to the call stack for every deferrable function you're in.
- To avoid annoying errors where you've defined an arg as deferred but
forgot to wrap the function in question.
On Fri, Jul 20, 2018 at 3:39 PM, Jonathan Fine <jfine2358 at gmail.com> wrote:
> Hi Peter
>
> You make the very good point, that
>
> > subfunction_1 may be written by someone totally different from the
> author of
> > main_function, and may even be in a different codebase. For the author
> of
> > subfunction_1, it makes no sense to use the "None" approach instead of
> > python's normal default mechanism (since all arguments here are
> immutables).
>
> Good point. To rephrase, what should we do if we want to use a third
> party or legacy function, which begins
> ===
> def fn(a=1, b=2, c=3):
> # function body
> ===
>
> We can solve this by defining a function decorator. Suppose we have a
> function fix_it, whose argument and return value are both functions.
> The basic specification of fix_it is that
> ---
> fixed_fn = fix_it(fn)
> ---
> is in practice equivalent to
> ---
> def fixed_fn(a=None, b=None, c=None):
> if a is None: a = 1
> if b is None: b = 2
> if c is None: c = 3
> # function body for fn
> # or if you prefer
> return fn(a, b, c)
> ---
>
> An aside. We can code fix_it by using
> https://docs.python.org/3/library/inspect.html
> ===
> >>> import inspect
> >>> def fn(a=1, b=2, c=3): pass
> ...
> >>> str(inspect.signature(fn))
> '(a=1, b=2, c=3)'
> ===
>
> You could also use with new code, like so:
> ---
> @fix_it
> def fn(a=1, b=2, c=3):
> # function body
> ---
>
> I think this helps solve your problem. Is there, Peter, anything else
> that would be left to do (except, of course, write the fix_it
> function).
>
> Thank you again for your problem and comments.
>
> --
> Jonathan
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20180720/34c86253/attachment.html>
More information about the Python-ideas
mailing list