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_co...>, 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@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