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 <jfine2...@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 >
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/